Express: migratsiya va seed

Bazani ulash darsida jadval db/index.js ichida, CREATE TABLE IF NOT EXISTS bilan yaratildi. Ilova yolg’iz ishlaganda bu yetadi. Endi tasavvur qiling: vazifaga “muhimlik darajasi” ustunini qo’shmoqchisiz. CREATE TABLE ni tahrirlaysiz — lekin jadval allaqachon mavjud, IF NOT EXISTS uni chetlab o’tadi va yangi ustun paydo bo’lmaydi.

Hamkasbingizning kompyuterida esa jadval yo’q edi, unda yangi ustun bilan yaratiladi. Ikki mashinada ikki xil baza.

Migratsiya nima

Asosiy g’oya: baza tuzilishi ham kod, va u ham git da saqlanadi. Yangi dasturchi loyihani klonlab, bitta buyruq yuritadi va bazasi hammanikiga mos bo’ladi.

Yondashuv Muammo
Qo’lda CREATE TABLE yozish Har mashinada boshqacha baza
SQL ni chatda yuborish Kim bajardi, kim bajarmadi — noma’lum
Migratsiya fayllari Tarix git da, bajarilgani bazada qayd etilgan

Ulanishni soddalashtirish

Jadval yaratish endi migratsiyaning ishi, shuning uchun db/index.js faqat ulanish bilan qoladi:

// db/index.js
const path = require("path");
const { DatabaseSync } = require("node:sqlite");

const databasePath = path.join(__dirname, "..", "tasks.db");
const database = new DatabaseSync(databasePath);

module.exports = database;

CREATE TABLE qatorlari o’chdi. Bu muhim chegara: ilova ishga tushganda baza tuzilishini o’zgartirmaydi. Tuzilishni faqat siz, ataylab, npm run migrate bilan o’zgartirasiz.

Birinchi migratsiya

mkdir migrations

migrations/001-create-tasks.js:

// migrations/001-create-tasks.js
module.exports = {
  name: "001-create-tasks",
  up(database) {
    database.exec(`
      CREATE TABLE IF NOT EXISTS tasks (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        title TEXT NOT NULL,
        is_done INTEGER NOT NULL DEFAULT 0,
        created_at TEXT NOT NULL DEFAULT (datetime('now'))
      )
    `);
  },
};

Fayl nomidagi 001 — tartib raqami. Migratsiyalar ketma-ketligi muhim: ustun qo’shishdan oldin jadval mavjud bo’lishi kerak.

up funksiyasining nomi ham konvensiya: “tuzilishni oldinga surish” degani. Ba’zi tizimlarda down ham bo’ladi — o’zgarishni qaytarish uchun.

Migratsiyalarni bajaruvchi skript

migrate.js — loyiha ildizida:

// migrate.js
const fs = require("fs");
const path = require("path");
const database = require("./db");

// Bajarilgan migratsiyalar shu jadvalda qayd etiladi
database.exec(`
  CREATE TABLE IF NOT EXISTS migrations (
    name TEXT PRIMARY KEY,
    run_at TEXT NOT NULL DEFAULT (datetime('now'))
  )
`);

const migrationsDir = path.join(__dirname, "migrations");
const files = fs
  .readdirSync(migrationsDir)
  .filter((file) => file.endsWith(".js"))
  .sort();

const isApplied = database.prepare("SELECT name FROM migrations WHERE name = ?");
const markApplied = database.prepare("INSERT INTO migrations (name) VALUES (?)");

let appliedCount = 0;

for (const file of files) {
  const migration = require(path.join(migrationsDir, file));

  if (isApplied.get(migration.name)) {
    console.log("O'tkazib yuborildi:", migration.name);
    continue;
  }

  migration.up(database);
  markApplied.run(migration.name);
  appliedCount = appliedCount + 1;
  console.log("Bajarildi:", migration.name);
}

console.log(`Jami yangi migratsiya: ${appliedCount}`);

Skript uch ishni bajaradi: migrations jadvalini tayyorlaydi, papkadagi fayllarni tartib bilan o’qiydi, bajarilmaganini ishga tushirib qayd etadi. fs.readdirSync va path.join fayl bilan ishlash darsida ko’rilgan.

package.json ga buyruq qo’shing:

{
  "scripts": {
    "start": "node app.js",
    "dev": "nodemon app.js",
    "migrate": "node migrate.js",
    "seed": "node seed.js"
  }
}
npm run migrate
Bajarildi: 001-create-tasks
Jami yangi migratsiya: 1

Qayta yurgizing:

npm run migrate
O'tkazib yuborildi: 001-create-tasks
Jami yangi migratsiya: 0

Ikkinchi marta hech narsa bajarilmadi — migrations jadvalida yozuv bor. Buyruqni xohlagancha takrorlash xavfsiz.

Ikkinchi migratsiya: ustun qo’shish

Endi haqiqiy o’zgarish qilamiz. migrations/002-add-priority.js:

// migrations/002-add-priority.js
module.exports = {
  name: "002-add-priority",
  up(database) {
    database.exec(
      "ALTER TABLE tasks ADD COLUMN priority INTEGER NOT NULL DEFAULT 3"
    );
  },
};
npm run migrate
O'tkazib yuborildi: 001-create-tasks
Bajarildi: 002-add-priority
Jami yangi migratsiya: 1

Birinchi migratsiya chetlab o’tildi, ikkinchisi bajarildi. Jadvalda allaqachon ma’lumot bo’lsa, ular yo’qolmaydi: eski qatorlar priority ustuniga 3 qiymatini oladi — DEFAULT shuni aytadi.

Modelga yangi ustunni qo’shish

Baza o’zgardi, endi model qatlami ham bilishi kerak. models/task.js dagi toTask ga bitta qator qo’shiladi:

function toTask(row) {
  return {
    id: row.id,
    title: row.title,
    isDone: row.is_done === 1,
    priority: row.priority,
    createdAt: row.created_at,
  };
}

Model qatlami shu yerda o’zini oqlaydi: butun ilovada priority bitta faylda paydo bo’ldi, marshrutlarga qo’l tegmadi.

Seed — sinov ma’lumoti

Bo’sh baza bilan ishlash noqulay: har sinovda qo’lda vazifa qo’shasiz. seed.js:

// seed.js
const database = require("./db");

const sampleTasks = [
  { title: "Express o'rganish", isDone: true, priority: 1 },
  { title: "Bazani ulash", isDone: true, priority: 2 },
  { title: "Migratsiya yozish", isDone: false, priority: 1 },
  { title: "Testlarni yozish", isDone: false, priority: 4 },
];

// Eski sinov ma'lumotini tozalaymiz
database.exec("DELETE FROM tasks");
database.exec("DELETE FROM sqlite_sequence WHERE name = 'tasks'");

const insert = database.prepare(
  "INSERT INTO tasks (title, is_done, priority) VALUES (?, ?, ?)"
);

for (const task of sampleTasks) {
  insert.run(task.title, task.isDone ? 1 : 0, task.priority);
}

const count = database.prepare("SELECT COUNT(*) AS total FROM tasks").get();
console.log(`Seed tugadi. Jadvalda ${count.total} ta vazifa bor.`);
npm run seed
Seed tugadi. Jadvalda 4 ta vazifa bor.

Skriptni qancha yursangiz ham natija bir xil: eski yozuvlar o’chadi, o’sha to’rttasi qayta qo’shiladi. DELETE FROM sqlite_sequence qatori id sanagichini nolga qaytaradi — usiz har npm run seed dan keyin raqamlar 5, 6, 7 deb davom etardi.

Tekshiring:

curl http://localhost:3000/api/tasks
[{"id":1,"title":"Express o'rganish","isDone":true,"priority":1,"createdAt":"2026-09-12 14:04:41"},{"id":2,"title":"Bazani ulash","isDone":true,"priority":2,"createdAt":"2026-09-12 14:04:41"},{"id":3,"title":"Migratsiya yozish","isDone":false,"priority":1,"createdAt":"2026-09-12 14:04:41"},{"id":4,"title":"Testlarni yozish","isDone":false,"priority":4,"createdAt":"2026-09-12 14:04:41"}]

Yangi dasturchining yo’li

Migratsiya tizimining butun qiymati shu uch buyruqda ko’rinadi:

npm install
npm run migrate
npm run seed

Baza fayli git da yo’q, lekin uni tiklash uchun hech kimdan hech narsa so’ramaysiz. Tuzilish migrations/ da, sinov ma’lumoti seed.js da — ikkalasi ham repozitoriyda.

Serverda esa npm run seed tushirilmaydi, faqat npm run migrate bajariladi: tuzilish yangilanadi, ma’lumot tegilmaydi.

Muhit migrate seed
Kompyuteringiz Ha Ha
Sinov serveri Ha Ha
Ishlab turgan server Ha Yo’q

Amaliy mashq

task-app loyihasida davom eting:

  1. db/index.js dan CREATE TABLE ni olib tashlab, uni migrations/001-create-tasks.js ga ko’chiring;
  2. migrate.js ni yozing va npm run migrate ni ikki marta yurgizib, ikkinchisida hech narsa bajarilmasligini ko’ring;
  3. 002-add-priority.js ni yozib, ALTER TABLE bilan yangi ustun qo’shing;
  4. migrations jadvalidan 002 qatorini qo’lda o’chirib (DELETE FROM migrations WHERE name = '002-add-priority'), npm run migrate ni qayta yurgizing va duplicate column name xatosini o’z ko’zingiz bilan ko’ring;
  5. toTask ga priority ni qo’shib, curl javobida ko’rinishini tasdiqlang;
  6. seed.js yozib, uni ikki marta yurgizing — vazifalar soni har safar to’rtta bo’lib qolishi kerak.

4-qadam noqulay ko’rinadi, lekin aynan u migratsiya jadvali nimani himoya qilishini ko’rsatadi.

Qisqacha xulosa

  • Jadvalni ilova ishga tushganda yaratish turli mashinalarda turli baza tuzilishiga olib keladi.
  • Migratsiya — raqamlangan, bir marta bajariladigan tuzilish o’zgarishi; seed — ma’lumot to’ldirish.
  • Bajarilgan migratsiya nomi bazadagi migrations jadvalida qayd etiladi va shuning uchun takroran bajarilmaydi.
  • Fayl nomi 001, 002 shaklida raqamlanadi — alifbo tartibi to’g’ri ishlashi uchun.
  • Bajarilgan migratsiya tahrirlanmaydi — har o’zgarish uchun yangi fayl yoziladi.
  • ALTER TABLE ... ADD COLUMN da IF NOT EXISTS yo’q, ikkinchi urinish duplicate column name xatosini beradi.
  • seed ishlab turgan serverda yurgizilmaydi — u bor ma’lumotni o’chiradi.

Keyingi darsda sessiya va cookie — server kim kelganini qanday eslab qolishi.

Bu dars foydali bo'ldimi?

marta ko'rildi