Node.js va SQLite: baza bilan ishlash
CLI dastur darsida vazifalarni todos.json
fayliga saqlagansiz. Bu kichik ro’yxatda ishlaydi. Ammo ma’lumot
o’n mingtaga yetganda muammo boshlanadi: bitta vazifani o’zgartirish
uchun ham butun fayl o’qiladi, JSON.parse qilinadi va qaytadan
yoziladi.
Baza aynan shu muammoni hal qiladi: kerakli qatorni butun faylni o’qimasdan topadi va yangilaydi.
node:sqlite — o’rnatish shart emas
Node.js’da SQLite ichiga qurilgan. npm orqali hech narsa o’rnatilmaydi:
const { DatabaseSync } = require("node:sqlite");
const database = new DatabaseSync(":memory:");
database.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT)");
console.log("Jadval yaratildi");
database.close();
node sqlite-check.js
Jadval yaratildi
(node:10640) ExperimentalWarning: SQLite is an experimental feature and might change at any time
":memory:" — baza faylsiz, faqat xotirada yaratiladi. Dastur yopilgach
yo’qoladi, shuning uchun sinash uchun qulay.
Fayldagi baza va jadval
Endi haqiqiy fayl bilan ishlaymiz. db-demo.js:
const { DatabaseSync } = require("node:sqlite");
// Fayl bo'lmasa o'zi yaratiladi
const database = new DatabaseSync("books.db");
database.exec(`
CREATE TABLE IF NOT EXISTS books (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
author TEXT NOT NULL,
year INTEGER
)
`);
console.log("Jadval tayyor");
database.close();
node db-demo.js
Jadval tayyor
Papkada books.db fayli paydo bo’ladi — butun baza shu faylda.
IF NOT EXISTS qo’shilgani muhim: dastur ikkinchi marta ishga
tushganda jadval bor bo’lgani uchun xato chiqmaydi.
Jadval tuzilishi CREATE TABLE darsidagi yozuvning o’zi. SQL bilimi shu yerda to’g’ridan-to’g’ri ishlaydi.
exec va prepare farqi
Modulda ikki xil usul bor va ularni chalkashtirmaslik kerak:
| Metod | Qachon | Qiymat qabul qiladimi |
|---|---|---|
database.exec() |
Jadval yaratish, o’chirish | Yo’q |
database.prepare() |
Ma’lumot qo’shish, o’qish, yangilash | Ha |
Ma’lumot qo’shish — run
const { DatabaseSync } = require("node:sqlite");
const database = new DatabaseSync("books.db");
const insert = database.prepare(
"INSERT INTO books (title, author, year) VALUES (?, ?, ?)"
);
const added = insert.run("O'tkan kunlar", "Abdulla Qodiriy", 1926);
console.log("Qo'shildi, id:", added.lastInsertRowid);
insert.run("Mehrobdan chayon", "Abdulla Qodiriy", 1929);
insert.run("Shum bola", "G'afur G'ulom", 1936);
database.close();
node insert-demo.js
Qo'shildi, id: 1
So’rovdagi ? belgilari — qiymat o’rni. run() ga berilgan argumentlar
o’sha o’rinlarga tartib bo’yicha tushadi.
run() natijasida ikkita foydali maydon qaytadi:
| Maydon | Nima |
|---|---|
lastInsertRowid |
Yangi qatorning id si |
changes |
O’zgargan qatorlar soni |
Bir marta tayyorlangan insert uch marta ishlatilgani ham muhim —
har safar qaytadan tayyorlash shart emas.
Ma’lumot o’qish — all va get
const { DatabaseSync } = require("node:sqlite");
const database = new DatabaseSync("books.db");
// Hamma qatorlar — massiv qaytadi
const all = database.prepare("SELECT * FROM books ORDER BY year").all();
console.log("Jami kitoblar:", all.length);
for (const book of all) {
console.log(`${book.year} — ${book.title} (${book.author})`);
}
// Bitta qator — obyekt qaytadi
const one = database
.prepare("SELECT * FROM books WHERE author = ?")
.get("G'afur G'ulom");
console.log("Topildi:", one.title);
database.close();
node select-demo.js
Jami kitoblar: 3
1926 — O'tkan kunlar (Abdulla Qodiriy)
1929 — Mehrobdan chayon (Abdulla Qodiriy)
1936 — Shum bola (G'afur G'ulom)
Topildi: Shum bola
SELECT va ORDER BY yozuvi select darsidagi bilan bir
xil — o’zgargani faqat chaqirish usuli.
| Metod | Qaytaradi | Hech narsa topilmasa |
|---|---|---|
.all() |
Qatorlar massivi | Bo’sh massiv [] |
.get() |
Bitta qator obyekti | undefined |
.run() |
O’zgarish haqida ma’lumot | — |
Yangilash va o’chirish
const { DatabaseSync } = require("node:sqlite");
const database = new DatabaseSync("books.db");
const updated = database
.prepare("UPDATE books SET year = ? WHERE title = ?")
.run(1925, "O'tkan kunlar");
console.log("O'zgargan qatorlar:", updated.changes);
const deleted = database
.prepare("DELETE FROM books WHERE year < ?")
.run(1900);
console.log("O'chirilgan qatorlar:", deleted.changes);
database.close();
node update-demo.js
O'zgargan qatorlar: 1
O'chirilgan qatorlar: 0
changes qiymati 0 bo’lsa — shartga mos qator topilmagan. Bu xato
emas, lekin dastur buni sezishi kerak: “o’zgartirildi” deb xabar
bermasdan oldin changes ni tekshiring.
Eng muhim qism: parametrli so’rov
Endi ? belgisi nega kerakligini ko’rsatamiz. Bu darsning eng muhim
bo’limi.
Tasavvur qiling, qidiruv so’zi foydalanuvchidan keladi. Uni so’rovga yopishtirib yozish mumkin edi. Nima bo’lishini sinaymiz:
const { DatabaseSync } = require("node:sqlite");
const database = new DatabaseSync(":memory:");
database.exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)");
database.prepare("INSERT INTO users (name) VALUES (?)").run("Aziz");
database.prepare("INSERT INTO users (name) VALUES (?)").run("Malika");
// Foydalanuvchi oddiy ism o'rniga SQL bo'lagini yozdi
const userInput = "Aziz' OR '1'='1";
const rows = database
.prepare("SELECT * FROM users WHERE name = ?")
.all(userInput);
console.log("Parametr bilan topilgan qatorlar:", rows.length);
const normal = database
.prepare("SELECT * FROM users WHERE name = ?")
.all("Aziz");
console.log("Oddiy qidiruv:", normal.length, normal[0].name);
database.close();
node injection-demo.js
Parametr bilan topilgan qatorlar: 0
Oddiy qidiruv: 1 Aziz
Natijaga diqqat qiling. Hujum uchun yozilgan matn 0 ta qator qaytardi.
Sabab: ? orqali uzatilgan qiymat SQL kodi sifatida o’qilmaydi.
Baza uni butunligicha oddiy ism deb qabul qildi va shunday ismli
foydalanuvchi topilmadi. Ya’ni ' va OR belgilari o’z kuchini
yo’qotdi.
Nomlangan parametrlar
Parametr ko’payganda ? belgilari chalkashadi. Ularga nom berish
mumkin:
const { DatabaseSync } = require("node:sqlite");
const database = new DatabaseSync("books.db");
const found = database
.prepare(
"SELECT * FROM books WHERE author = :author AND year >= :minYear"
)
.all({ author: "Abdulla Qodiriy", minYear: 1925 });
console.log("Topilgan kitoblar:", found.length);
for (const book of found) {
console.log(`${book.title} — ${book.year}`);
}
database.close();
node named-demo.js
Topilgan kitoblar: 2
O'tkan kunlar — 1925
Mehrobdan chayon — 1929
Himoya darajasi bir xil, o’qish esa qulayroq.
Jadvallarni birlashtirish
SQL ning kuchi bir nechta jadval bilan ochiladi:
const { DatabaseSync } = require("node:sqlite");
const database = new DatabaseSync(":memory:");
database.exec(`
CREATE TABLE authors (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE novels (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
authorId INTEGER,
FOREIGN KEY (authorId) REFERENCES authors(id)
);
`);
database.prepare("INSERT INTO authors (id, name) VALUES (?, ?)").run(1, "Abdulla Qodiriy");
database.prepare("INSERT INTO novels (title, authorId) VALUES (?, ?)").run("O'tkan kunlar", 1);
database.prepare("INSERT INTO novels (title, authorId) VALUES (?, ?)").run("Mehrobdan chayon", 1);
const rows = database
.prepare(
`SELECT novels.title, authors.name AS authorName
FROM novels
JOIN authors ON novels.authorId = authors.id`
)
.all();
for (const row of rows) {
console.log(`${row.title} — ${row.authorName}`);
}
database.close();
node join-demo.js
O'tkan kunlar — Abdulla Qodiriy
Mehrobdan chayon — Abdulla Qodiriy
JOIN yozuvi join darsidagi bilan aynan bir xil.
Amaliy mashq
node-start papkasida bajaring:
books.dbfaylini yaratib,booksjadvaliniIF NOT EXISTSbilan qo’shing hamda skriptni ikki marta ishga tushiring;preparevarunbilan uchta kitob qo’shib,lastInsertRowidqiymatlarini chiqaring;.all()bilan hamma kitobni,.get()bilan bittasini o’qing va qaytgan turlarni solishtiring;- Mavjud bo’lmagan
idbilan.get()chaqirib,undefinedholatini tekshiruv bilan qamrang; UPDATEso’rovini bajarib,changesqiymatiga qarab xabar chiqaring;"Aziz' OR '1'='1"matnini?orqali qidiruvga berib, natija bo’sh ekanini o’z ko’zingiz bilan ko’ring.
6-qadam eng muhimi: parametrli so’rov nega ishlashini bir marta ko’rgan odam uni boshqa unutmaydi.
Qisqacha xulosa
node:sqliteNode.js ichida keladi —npm installqilinmaydi.- Modul eksperimental: ishlaydi, lekin ogohlantirish chiqaradi.
- Butun baza bitta faylda saqlanadi,
":memory:"esa faqat xotirada. exec()qiymatsiz SQL uchun,prepare()qiymat bilan ishlaydigan so’rovlar uchun..all()massiv,.get()bitta obyekt yokiundefined,.run()o’zgarish ma’lumotini qaytaradi.- Qiymat har doim
?yoki nomlangan parametr orqali beriladi — so’rov matniga yopishtirilmaydi. - Parametrli so’rovda hujum uchun yozilgan matn oddiy qiymat bo’lib qoladi va hech nima topmaydi.
Keyingi darsda xatolar va jurnal — nosozlikni qanday qayd etish va topish.