Node.js bilan bazaga ulanish
Endi eng amaliy qismga keldik: bazani Node.js dasturingizdan qanday ishlatish. Buning uchun maxsus kutubxona (driver) kerak. PostgreSQL uchun eng mashhuri โ pg. Ushbu darsda ulanish, so'rov yuborish, xavfsizlik va to'liq CRUD amallarini o'rganamiz.
pg kutubxonasini o'rnatish
PostgreSQL bilan ishlash uchun pg paketini npm orqali o'rnatamiz:
npm install pg
Bu kutubxona Node.js'dan PostgreSQL serveriga ulanish, so'rov yuborish va natijani JavaScript obyektlari sifatida olish imkonini beradi.
Oddiy ulanish: Client
Eng oddiy usul โ bitta Client yaratish. Unga ulanish ma'lumotlarini beramiz:
const { Client } = require("pg");
const client = new Client({
host: "localhost",
port: 5432,
user: "postgres",
password: "parol",
database: "mydb"
});
async function main() {
await client.connect(); // bazaga ulanish
const res = await client.query("SELECT NOW()"); // so'rov
console.log(res.rows); // natija
await client.end(); // ulanishni yopish
}
main();
Bu yerda muhim jihatlar: connect() ulanadi, query() so'rov yuboradi, end() ulanishni yopadi. Barchasi async/await bilan ishlaydi, chunki baza bilan aloqa vaqt oladi (asinxron).
process.env.DB_PASSWORD) yoki .env faylda saqlang. Aks holda parol kod tarixida (git) ochiq qoladi.So'rov natijasi bilan ishlash
client.query() obyekt qaytaradi. Uning eng muhim xususiyati โ rows, ya'ni natija qatorlari massivi. Har bir qator oddiy JavaScript obyekti:
const res = await client.query("SELECT id, name FROM users");
console.log(res.rows);
// [ { id: 1, name: 'Ali' }, { id: 2, name: 'Vali' } ]
console.log(res.rows.length); // qatorlar soni
console.log(res.rows[0].name); // 'Ali'
Ko'rib turganingizdek, SQL natijasi to'g'ridan-to'g'ri JavaScript obyektlariga aylanadi โ ustun nomlari obyekt kalitlariga aylanadi. Bu bilan ishlash juda qulay.
SQL injection โ jiddiy xavf
Endi eng muhim mavzu โ xavfsizlik. Aytaylik, foydalanuvchidan kelgan ism bo'yicha qidirmoqchisiz. Vasvasaga tushib, so'rovni shunday yozishingiz mumkin:
// XAVFLI! Hech qachon bunday qilmang!
const name = req.query.name; // foydalanuvchidan kelgan
const res = await client.query(
"SELECT * FROM users WHERE name = '" + name + "'"
);
Muammo shundaki, foydalanuvchi name o'rniga SQL kodini yuborishi mumkin. Masalan, u quyidagi qiymatni yuborsa:
'; DROP TABLE users; --
Unda so'rov shunday bo'ladi va butun jadval o'chib ketadi:
SELECT * FROM users WHERE name = ''; DROP TABLE users; --'
Yechim: parametrlangan so'rovlar
To'g'ri yechim โ parametrlangan so'rovlar (parameterized queries). Qiymatlarni matnga qo'shish o'rniga, so'rovda $1, $2 kabi joy egallovchilar (placeholder) qo'yamiz, qiymatlarni esa alohida massivda beramiz:
// TO'G'RI va XAVFSIZ usul
const name = req.query.name;
const res = await client.query(
"SELECT * FROM users WHERE name = $1",
[name]
);
Bu yerda $1 โ birinchi parametr uchun joy, [name] esa uning qiymati. Kutubxona qiymatni xavfsiz tarzda joylashtiradi โ u har doim oddiy qiymat sifatida qaraladi, hech qachon SQL kod sifatida bajarilmaydi. SQL injection imkonsiz bo'ladi.
// Bir necha parametr bilan
const res = await client.query(
"SELECT * FROM users WHERE age > $1 AND is_active = $2",
[25, true]
);
+) orqali emas. Bu backend xavfsizligining eng asosiy qoidalaridan biri.To'liq CRUD misoli
Endi to'rtta asosiy amalni (CREATE, READ, UPDATE, DELETE โ CRUD) parametrlangan so'rovlar bilan yozamiz. Bular real loyihada ishlatiladigan funksiyalar:
const { Client } = require("pg");
const client = new Client({ /* sozlamalar */ });
// CREATE โ yangi foydalanuvchi qo'shish
async function createUser(name, email, age) {
const res = await client.query(
"INSERT INTO users (name, email, age) VALUES ($1, $2, $3) RETURNING *",
[name, email, age]
);
return res.rows[0]; // qo'shilgan qator
}
// READ โ id bo'yicha o'qish
async function getUser(id) {
const res = await client.query(
"SELECT * FROM users WHERE id = $1",
[id]
);
return res.rows[0]; // topilgan qator (yoki undefined)
}
// UPDATE โ yoshni yangilash
async function updateAge(id, age) {
const res = await client.query(
"UPDATE users SET age = $1 WHERE id = $2 RETURNING *",
[age, id]
);
return res.rows[0];
}
// DELETE โ o'chirish
async function deleteUser(id) {
const res = await client.query(
"DELETE FROM users WHERE id = $1",
[id]
);
return res.rowCount; // o'chirilgan qatorlar soni
}
RETURNING * โ bu PostgreSQL'ning foydali imkoniyati. INSERT/UPDATE/DELETE'dan keyin o'zgargan qatorni qaytaradi. Masalan, INSERT ... RETURNING * avtomatik yaratilgan idni ham qaytaradi, shuning uchun uni alohida so'rov bilan olishga hojat yo'q.Bu funksiyalarni ishlatish:
async function main() {
await client.connect();
const yangi = await createUser("Ali", "ali@mail.com", 25);
console.log("Yaratildi:", yangi);
const topilgan = await getUser(yangi.id);
console.log("Topildi:", topilgan);
await updateAge(yangi.id, 26);
await deleteUser(yangi.id);
await client.end();
}
main().catch(err => console.error("Xato:", err));
try/catch yoki .catch() bilan o'rab, xatolarni to'g'ri qayta ishlash muhim. Yuqorida .catch() butun mainni himoya qiladi.Connection Pool โ ulanishlar havzasi
Yuqorida bitta Client ishlatdik. Lekin veb-serverda bir vaqtda yuzlab so'rov keladi. Har so'rov uchun yangi ulanish ochish sekin va samarasiz. Yechim โ Pool (ulanishlar havzasi):
const { Pool } = require("pg");
const pool = new Pool({
host: "localhost",
user: "postgres",
password: process.env.DB_PASSWORD,
database: "mydb",
max: 20 // eng ko'pi 20 ta ulanish
});
// query'ni to'g'ridan-to'g'ri pool'dan chaqiramiz
async function getUsers() {
const res = await pool.query("SELECT * FROM users");
return res.rows;
}
Pool oldindan bir nechta ulanishni ochib qo'yadi va ularni qayta ishlatadi. So'rov kelganda tayyor ulanishni beradi, tugagach uni havzaga qaytaradi. Bu ancha tez va samarali.
Client emas, Pool ishlatiladi. pool.query() avtomatik ulanish oladi va qaytaradi โ siz connect/end haqida o'ylashingiz shart emas.MongoDB uchun: mongoose (qisqacha)
Agar MongoDB ishlatsangiz, Node.js'da eng mashhur kutubxona โ mongoose. U ulanishni va ma'lumot bilan ishlashni osonlashtiradi:
npm install mongoose
const mongoose = require("mongoose");
await mongoose.connect("mongodb://localhost:27017/mydb");
// Sxema va model
const User = mongoose.model("User", new mongoose.Schema({
name: String,
email: String,
age: Number
}));
// CRUD
const yangi = await User.create({ name: "Ali", age: 25 });
const hammasi = await User.find({ age: { $gt: 20 } });
await User.updateOne({ name: "Ali" }, { $set: { age: 26 } });
await User.deleteOne({ name: "Ali" });
Xulosa
- PostgreSQL uchun
pgkutubxonasi ishlatiladi:connect,query,end; - So'rov natijasi
res.rowsmassivida keladi โ har qator oddiy JavaScript obyekti; - SQL injection โ foydalanuvchi ma'lumotini SQL matniga to'g'ridan-to'g'ri qo'shishdan kelib chiqadigan jiddiy xavf;
- Yechim โ parametrlangan so'rovlar:
query("... WHERE id = $1", [id]); - To'liq CRUD funksiyalari
async/awaitbilan yoziladi;RETURNING *o'zgargan qatorni qaytaradi; - Real loyihada Pool (ulanishlar havzasi) ishlatiladi โ tez va samarali;
- MongoDB uchun
mongooseโ sxema, model va oson CRUD imkoniyatlarini beradi.