Database Migrations (Sequelize)
Muammo
Loyiha ishga tushdi. Foydalanuvchilar bor, ma'lumotlar bor. Endi users jadvaliga yangi phone ustuni qo'shish kerak.
Noto'g'ri yo'l: serverga kirib, qo'lda ALTER TABLE users ADD COLUMN phone VARCHAR(20) yozish. Bu bir marta ishlaydi — lekin:
- Jamoadagi boshqa dasturchi o'z kompyuterida bu o'zgarishni bilmaydi
- Staging serverda bu ustun yo'q, production da bor — xatolar boshlanadi
- 3 oy o'tib, "bu ustun qachon, nima uchun qo'shilgan?" degan savolga javob yo'q
Migration — bu ma'lumotlar bazasi o'zgarishlarini kod sifatida saqlash. Git orqali kuzatiladi, jamoa bilan baham ko'riladi, istalgan muhitda bir xil natija beradi.
Bu nima?
Migration — bu ma'lumotlar bazasiga qilinadigan o'zgarishni tasvirlovchi fayl. Har bir migration ikkita funksiyadan iborat:
up— o'zgarishni qo'llash (ustun qo'shish, jadval yaratish)down— o'zgarishni bekor qilish (ustun o'chirish, jadval o'chirish)
up ni ishga tushirsangiz — o'zgarish qo'llanadi. down ni ishga tushirsangiz — orqaga qaytadi.
Hayotiy o'xshatma
Tasavvur qiling: ofis binosi qurilmoqda. Har bir qurilish bosqichi alohida hujjatda yozilgan: "3-qavat qo'shildi", "lift o'rnatildi", "derazalar almashtrildi". Agar biror narsa noto'g'ri bo'lsa, hujjatga qarab orqaga qaytish mumkin. Yangi ishchi kelsa, barcha hujjatlarni ketma-ket bajarib, binoni to'liq tiklay oladi.
Migration ham xuddi shunday: yangi dasturchi loyihani clone qilib, npx sequelize-cli db:migrate deb yozsa — barcha o'zgarishlar ketma-ket qo'llanadi va uning bazasi siznikiga o'xshash bo'ladi.
Nima uchun sync: true yetarli emas?
NestJS + Sequelize da sync: { force: true } yoki sync: { alter: true } ishlatish mumkin — bu modellardan avtomatik jadval yaratadi. Lekin:
force: true— har safar barcha jadvallarni o'chirib qayta yaratadi. Production da halokatli.alter: true— mavjud jadvalga o'zgarish kiritadi, lekin ba'zi hollarda ma'lumotlarni yo'qotishi mumkin va ishonchsiz.- Ikkalasi ham o'zgarishlar tarixini saqlamaydi.
Migration esa aniq, nazorat ostidagi o'zgarish beradi.
O'rnatish
npm install --save-dev sequelize-cli
Loyiha ildizida .sequelizerc fayli yarating:
// .sequelizerc
const path = require('path');
module.exports = {
config: path.resolve('src/database', 'config.js'),
'migrations-path': path.resolve('src/database', 'migrations'),
'seeders-path': path.resolve('src/database', 'seeders'),
};
// src/database/config.js
module.exports = {
development: {
username: process.env.DB_USER || 'postgres',
password: process.env.DB_PASS || 'password',
database: process.env.DB_NAME || 'myapp_dev',
host: process.env.DB_HOST || 'localhost',
dialect: 'postgres',
},
production: {
username: process.env.DB_USER,
password: process.env.DB_PASS,
database: process.env.DB_NAME,
host: process.env.DB_HOST,
dialect: 'postgres',
},
};
Migration yaratish va yozish
npx sequelize-cli migration:generate --name create-users-table
Bu src/database/migrations/20260508120000-create-users-table.js faylini yaratadi:
// migrations/20260508120000-create-users-table.js
'use strict';
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('users', {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true,
},
name: {
type: Sequelize.STRING,
allowNull: false,
},
email: {
type: Sequelize.STRING,
allowNull: false,
unique: true,
},
createdAt: {
type: Sequelize.DATE,
allowNull: false,
},
updatedAt: {
type: Sequelize.DATE,
allowNull: false,
},
});
},
async down(queryInterface) {
await queryInterface.dropTable('users'); // ← up ni bekor qiladi
},
};
Mavjud jadvalga ustun qo'shish
npx sequelize-cli migration:generate --name add-phone-to-users
// migrations/20260509100000-add-phone-to-users.js
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.addColumn('users', 'phone', { // ← ustun qo'shish
type: Sequelize.STRING(20),
allowNull: true,
});
},
async down(queryInterface) {
await queryInterface.removeColumn('users', 'phone'); // ← ustunni o'chirish
},
};
Migrationlarni ishga tushirish
# Barcha yangi migrationlarni qo'llash
npx sequelize-cli db:migrate
# Oxirgi migrationni bekor qilish
npx sequelize-cli db:migrate:undo
# Barcha migrationlarni bekor qilish
npx sequelize-cli db:migrate:undo:all
# Qaysi migrationlar bajarilganini ko'rish
npx sequelize-cli db:migrate:status
Sequelize bajarilgan migrationlarni
SequelizeMetajadvalida saqlaydi. Bu jadval avtomatik yaratiladi va har bir migration nomi yoziladi. Shu orqali qaysi migrationlar allaqachon bajarilganini biladi.
NestJS da sync ni o'chirish
Migrationlardan foydalanganda sync ni o'chirib qo'ying:
// app.module.ts
SequelizeModule.forRoot({
dialect: 'postgres',
// ...
models: [User, Post],
sync: { force: false }, // ← yoki umuman yozmang
autoLoadModels: true,
}),
Seeders — test ma'lumotlari
Seeder — bu bazaga boshlang'ich yoki test ma'lumotlarini qo'shuvchi fayl. Migration bilan bir xil tuzilma, lekin maqsad boshqa.
npx sequelize-cli seed:generate --name demo-users
// seeders/20260508130000-demo-users.js
module.exports = {
async up(queryInterface) {
await queryInterface.bulkInsert('users', [
{ name: 'Ali Karimov', email: 'ali@example.com', createdAt: new Date(), updatedAt: new Date() },
{ name: 'Vali Rahimov', email: 'vali@example.com', createdAt: new Date(), updatedAt: new Date() },
]);
},
async down(queryInterface) {
await queryInterface.bulkDelete('users', null, {}); // ← barcha yozuvlarni o'chiradi
},
};
npx sequelize-cli db:seed:all # barcha seederlarni ishga tushirish
npx sequelize-cli db:seed:undo # oxirgi seederni bekor qilish
Tez-tez uchraydigan xatolar
1. Migration ishga tushmaydi — config.js topilmadi
Sabab: .sequelizerc fayli yo'q yoki noto'g'ri yo'l ko'rsatilgan. Loyiha ildizida .sequelizerc borligini tekshiring.
2. down da xato — jadval yoki ustun yo'q
Sabab: down funksiyasi up ni to'liq teskari bajarishi kerak. Agar up da ikkita ustun qo'shilgan bo'lsa, down da ikkitasini ham o'chirish kerak.
3. Migration bajarildi, lekin jadvalda o'zgarish yo'q
Sabab: Migration allaqachon SequelizeMeta da bor — Sequelize uni qayta bajarmaydi. Agar migration faylini o'zgartirgan bo'lsangiz, avval db:migrate:undo qiling, keyin qayta db:migrate.
4. Production da force: true qoldirilgan
Sabab: Deploy vaqtida barcha jadvallar o'chirildi. sync: { force: false } yoki umuman sync yozmang — faqat migrationlardan foydalaning.
5. createdAt / updatedAt migration da yo'q
Sabab: Sequelize bu maydonlarni avtomatik boshqaradi, lekin migration da qo'lda yozish kerak. Aks holda NOT NULL constraint xatosi chiqadi.
Xulosa
- Migration — ma'lumotlar bazasi o'zgarishlarini kod sifatida saqlash usuli
- Har bir migration
up(qo'llash) vadown(bekor qilish) funksiyalaridan iborat SequelizeMetajadvali qaysi migrationlar bajarilganini kuzatadi- Production da
sync: { force: true }ishlatmang — faqat migrationlar - Seeder — test va boshlang'ich ma'lumotlar uchun
Keyingi dars: 16-dars: TypeORM + MySQL — CRUD