PostgreSQL — pg moduli, connection pool

~20 daq · Express · Ma'lumotlar Bazasi

Ma'lumotlar bazasi nima uchun kerak?

Oldingi darslarda ma'lumotlarni xotirada saqladik — massiv ichida. Bu faqat server ishlayotgan vaqtda mavjud. Server qayta ishga tushsa — hamma narsa yo'qoladi.

Haqiqiy ilovada ma'lumotlar doimiy saqlanishi kerak. Buning uchun ma'lumotlar bazasi ishlatiladi. PostgreSQL — eng kuchli va keng tarqalgan ochiq manbali relyatsion ma'lumotlar bazasi.


pg moduli nima?

pg — Node.js dan PostgreSQL ga ulanish uchun rasmiy kutubxona. U Node.js va PostgreSQL o'rtasidagi ko'prik: siz JavaScript yozasiz, pg uni PostgreSQL tushungan formatga aylantiradi, natijani qaytaradi.

npm install pg

Ulanish — oddiy va pool

PostgreSQL ga ulanishning ikki usuli bor. Farqini tushunish muhim.

Oddiy ulanish — har so'rov uchun yangi ulanish ochiladi, tugagach yopiladi. Xuddi har safar do'konga borganda yangi yo'l qurish kabi — isrof va sekin.

Connection Pool — bir nechta ulanish oldindan ochiladi va qayta ishlatiladi. Xuddi taksi parki kabi — mashina bo'sh bo'lsa, darhol beriladi. Tugagach qaytariladi, boshqasiga beriladi.

Production da har doim pool ishlatiladi. Oddiy ulanish faqat skriptlar yoki bir martalik ishlar uchun.

// db.js
const { Pool } = require('pg');

const pool = new Pool({
  host:     process.env.DB_HOST     || 'localhost',
  port:     process.env.DB_PORT     || 5432,
  database: process.env.DB_NAME     || 'mydb',
  user:     process.env.DB_USER     || 'postgres',
  password: process.env.DB_PASSWORD || 'secret',
  max:      10,   // maksimal ulanishlar soni
  idleTimeoutMillis: 30000, // 30 soniya bo'sh tursa — yopiladi
});

module.exports = pool;

Bu fayl bir marta yaratiladi va butun loyihada ishlatiladi. pool ob'ekti ulanishlarni o'zi boshqaradi — siz har safar ulanish ochib-yopmasangiz ham bo'ladi.


Birinchi so'rov

const pool = require('./db');

async function getUsers() {
  const result = await pool.query('SELECT * FROM users');
  return result.rows; // natija — ob'ektlar massivi
}

pool.query() — SQL so'rovini bajaradi va natijani qaytaradi. result.rows — qatorlar massivi. Har bir qator — JavaScript ob'ekti, ustun nomlari kalit sifatida.

Masalan, users jadvalida id, name, email ustunlari bo'lsa:

result.rows
// [
//   { id: 1, name: 'Ali',  email: 'ali@example.com' },
//   { id: 2, name: 'Vali', email: 'vali@example.com' },
// ]

Express bilan birlashtirish

// routes/users.js
const express = require('express');
const router  = express.Router();
const pool    = require('../db');

router.get('/', async (req, res, next) => {
  try {
    const result = await pool.query('SELECT id, name, email FROM users');
    res.json(result.rows);
  } catch (err) {
    next(err);
  }
});

router.get('/:id', async (req, res, next) => {
  try {
    const result = await pool.query(
      'SELECT id, name, email FROM users WHERE id = $1',
      [req.params.id]
    );

    if (result.rows.length === 0) {
      return res.status(404).json({ message: 'Topilmadi' });
    }

    res.json(result.rows[0]);
  } catch (err) {
    next(err);
  }
});

module.exports = router;

$1, $2 — parametrlar. Qiymatlar ikkinchi argument — massiv sifatida beriladi. Bu SQL Injection dan himoya qiladi. Keyingi darsda batafsil.


Ulanishni tekshirish

Server ishga tushganda ma'lumotlar bazasiga ulanish muvaffaqiyatli bo'lganini tekshirish — yaxshi amaliyot:

// app.js
const pool = require('./db');

async function startServer() {
  try {
    await pool.query('SELECT 1'); // oddiy test so'rov
    console.log('Ma\'lumotlar bazasiga ulandi');

    app.listen(3000, () => {
      console.log('Server ishlamoqda');
    });
  } catch (err) {
    console.error('Ma\'lumotlar bazasiga ulanib bo\'lmadi:', err.message);
    process.exit(1); // ulanmasa — server ishga tushmaydi
  }
}

startServer();

Nima uchun bu muhim? Ma'lumotlar bazasiz server ishga tushsa — so'rovlar keladi, lekin hamma narsa xato beradi. Yaxshisi darhol to'xtatib, muammoni hal qilish.


Tez-tez uchraydigan xatolar

Parolni kod ichiga yozish:

// Xato — GitHub ga chiqsa, parol oshkor bo'ladi:
const pool = new Pool({ password: 'mysecretpassword' });

// To'g'ri — .env faylidan:
const pool = new Pool({ password: process.env.DB_PASSWORD });

result.rows o'rniga result qaytarish:

// Xato:
return result; // { rows: [...], rowCount: 2, ... } — keraksiz ma'lumotlar

// To'g'ri:
return result.rows; // faqat qatorlar

Bitta qator kutilganda massiv qaytarish:

// Xato:
const user = await pool.query('SELECT * FROM users WHERE id = $1', [id]);
return user; // massiv, ob'ekt emas

// To'g'ri:
const result = await pool.query('SELECT * FROM users WHERE id = $1', [id]);
return result.rows[0]; // birinchi (va yagona) qator

Xulosa

pg — Node.js dan PostgreSQL ga ulanish uchun. Connection Pool — ulanishlarni qayta ishlatadi, har so'rov uchun yangi ulanish ochilmaydi.

pool.query(sql, params) — SQL so'rovini bajaradi. Natija result.rows da — ob'ektlar massivi.

Parametrlar $1, $2 ko'rinishida — SQL Injection dan himoya.


Keyingi dars

14-dars: PostgreSQL — CRUD, parametrli so'rovlar, SQL Injection himoyasi