IlmHamroh
JavaScript Full-stack/27-qism. Ma'lumotlar bazasi chuqur: Postgres, ORM, Mongo, Redis33/65-dars18 daqiqa
Mundarija (32)

Sequelize: model, associations, include, Op va sequelize-cli migratsiyalari

Qisqacha: Sequelize — Node.js'ning eng eski mashhur ORM'laridan biri, Express loyihalarida ko'p uchraydi. Model sequelize.define() yoki Model.init() bilan yoziladi, bog'lanishlar — hasMany/belongsTo, bog'langan ma'lumot — include, shartlar — Op operatorlari. Migratsiya va seed — sequelize-cli. Biz o'lchagan tuzoqlar: CLI o'zbekcha Vazifa ni Vazifas qiladi, seeder takroriy ishga tushsa yiqiladi, sync({ alter: true }) ustunni o'chirdi va ON DELETE CASCADE ni jim SET NULL ga almashtirdi.

Bu darsda

  • Sequelize modelini define va Model.init shakllarida o'qiy va yoza olasiz.
  • hasMany/belongsTo, include va Op bilan so'rovlar yozasiz.
  • Validatsiya va hook'lar (beforeValidate) qanday ishlashini bilasiz.
  • sequelize-cli bilan migratsiya va seeder yaratib, qo'llaysiz.
  • Sequelize'ning to'rt jim tuzog'ini haqiqiy natijada ko'rasiz.

Oldin bilishingiz kerak: TypeORM, ORM, query builder va raw SQL, CommonJS va ESM bilan o'zaro ishlash, Parametrli so'rovlar va SQL injection.

1. Nega bu kerak?

O'tgan darsda NestJS'ning TypeORM'ini ko'rdik. Endi boshqa manzara: Malika fintech startapga kirdi. Ularning API'si 2019-yilda Express bilan yozilgan, papkalar — models/, migrations/, seeders/, config/config.json. Har model fayli module.exports = (sequelize, DataTypes) => { … } bilan boshlanadi. Bu — Sequelize.

Sequelize 2010-yillardan beri bor. U TypeScript'dan oldin tug'ilgan, shuning uchun uslubi — oddiy JavaScript va CommonJS. Bugun yangi loyihaga kamdan-kam tanlanadi, lekin eski Express loyihalarining katta qismi aynan shunda. Uni o'qiy olmaslik — ishning birinchi haftasida qotib qolish degani.

O'xshatish: eski uyni ta'mirlashga kelgan usta. U uyni o'zi qurmagan, lekin qaysi devor yuk ko'tarishini bilishi shart. Sequelize'da "yuk ko'taruvchi devorlar" — sync, seeder'lar va include + limit.

Maslahat: Darsdagi hamma natija — biz ishga tushirdik: Sequelize 6.37.8, sequelize-cli 6.6.5, pg 8.23.1, Node 24.21.0, PostgreSQL 17.6, Windows 11 (2026-10-25). Tezlik raqamlari — kanon o'lchovidan.

2. Loyiha tuzilmasi: sequelize-cli init

2.1 init

sequelize-cli — Sequelize'ning buyruq qatori vositasi. Yangi papkada:

bash
npm i sequelize@6.37.8 pg@8.23.1
npm i -D sequelize-cli@6.6.5
npx sequelize-cli init
text
Sequelize CLI [Node: 24.21.0, CLI: 6.6.5, ORM: 6.37.8]

Created "config\config.json"
Successfully created models folder at "C:\Users\…\seq\models".
Successfully created migrations folder at "C:\Users\…\seq\migrations".
Successfully created seeders folder at "C:\Users\…\seq\seeders".

To'rtta narsa paydo bo'ldi:

Papka/fayl Nima
config/config.json Muhitlar bo'yicha ulanish (development, test, production)
models/index.js Hamma modellarni yuklaydigan va bog'laydigan fayl
migrations/ Sxema o'zgarishlari
seeders/ Boshlang'ich ma'lumot

2.2 config.json — birinchi tuzoq

init yaratgan config.json ichida:

json
{
  "development": {
    "username": "root",
    "password": null,
    "database": "database_development",
    "host": "127.0.0.1",
    "dialect": "mysql"
  }
}

Ikki muammo. Sukut — MySQL. Va parol shu faylga yoziladi — fayl esa Git'ga tushadi. Eski loyihalarda config.json ichida haqiqiy prodakshn paroli turgani — tez-tez uchraydigan voqea. To'g'ri yo'l — use_env_variable:

json
{
  "development": {
    "use_env_variable": "DATABASE_URL", "dialect": "postgres"
  },
  "production": {
    "use_env_variable": "DATABASE_URL", "dialect": "postgres"
  }
}

Endi ulanish satri DATABASE_URL muhit o'zgaruvchisidan olinadi (24-qismdagi --env-file bilan bir xil g'oya).

3. Model: define va Model.init

3.1 Generator va pluralizatsiya

CLI model va migratsiyani birga yasaydi:

bash
npx sequelize-cli model:generate --name Vazifa \
  --attributes matn:text,bajarildi:boolean,egasiId:integer

Yaratilgan migratsiya (boshi):

js
module.exports = {
  async up(queryInterface, Sequelize) {
    await queryInterface.createTable('Vazifas', {
      id: { allowNull: false, autoIncrement: true,
        primaryKey: true, type: Sequelize.INTEGER },
      matn: { type: Sequelize.TEXT },
      // … bajarildi, egasiId, createdAt, updatedAt

'Vazifas' ga qarang. Sequelize model nomini inglizcha qoidalar bilan ko'plikka aylantiradi: Vazifa → Vazifas, Foydalanuvchi → Foydalanuvchis. U o'zbek tilini bilmaydi. Yana: hamma ustun NULL ga ruxsat beradi (allowNull yo'q), createdAt/updatedAt o'zi qo'shilgan, jadval nomi katta harf bilan — SQL'da har safar qo'shtirnoq kerak bo'ladi ("Vazifas").

Shuning uchun generatorni faqat shablon sifatida ishlating va jadval nomini aniq bering.

3.2 Model.init — klass shakli

model:generate yaratadigan shakl — Model dan meros olgan klass. Biz uni o'z jadvalimizga moslab tuzatdik (models/vazifa.js):

js
'use strict';
const { Model } = require('sequelize');
module.exports = (sequelize, DataTypes) => {
  class Vazifa extends Model {
    static associate(models) {
      Vazifa.belongsTo(models.Foydalanuvchi,
        { foreignKey: 'egasi_id', as: 'egasi' });
    }
  }
  Vazifa.init({
    matn: { type: DataTypes.TEXT, allowNull: false,
      validate: { len: [1, 100] } },
    bajarildi: { type: DataTypes.BOOLEAN, allowNull: false,
      defaultValue: false },
    yaratilganVaqt: { type: DataTypes.DATE,
      field: 'yaratilgan_vaqt' },
  }, {
    sequelize, modelName: 'Vazifa',
    tableName: 'vazifalar', timestamps: false,
  });
  return Vazifa;
};

Har sozlama nima qiladi:

  • tableName: 'vazifalar' — pluralizatsiyani o'chiradi, jadval nomi aniq.
  • timestamps: false — createdAt/updatedAt ni kutmaydi (bizda o'z yaratilgan_vaqt bor).
  • field: 'yaratilgan_vaqt' — JS'da yaratilganVaqt, bazada yaratilgan_vaqt (TypeORM'dagi name, Prisma'dagi @map).
  • validate: { len: [1, 100] } — JS tomonidagi tekshiruv, bazaga borishdan oldin.
  • static associate(models) — bog'lanishlar; uni models/index.js hamma modellar yuklangach chaqiradi.

id ni yozmadik — Sequelize id ni sukut bo'yicha qo'shadi.

3.3 define — funksiya shakli

Xuddi shu model eski uslubda (kanon tajribasidagi kabi):

js
const Vazifa = sequelize.define('Vazifa', {
  matn: DataTypes.TEXT,
  bajarildi: DataTypes.BOOLEAN,
}, { tableName: 'vazifalar', timestamps: false });

define va Model.init — bir xil natija. Eski kodda ikkalasini ham uchratasiz.

Tekshirib ko'ring: Modelda validate: { len: [1, 100] } bor. Bazadagi CHECK cheklovi endi keraksizmi?

Javob

Kerak. validate faqat Sequelize orqali yozilganda ishlaydi. Boshqa skript, psql, boshqa servis yoki queryInterface.bulkInsert (u validatsiyani chetlab o'tadi) — bazaga to'g'ridan-to'g'ri yozadi. Oxirgi himoya — bazadagi CHECK (CREATE TABLE va constraint'lar).

4. Migratsiya va seeder

sequelize-cli'da ikki xil fayl bor va ular holat jadvaliga har xil munosabatda. Diagrammaga qarang — bu bo'limning hamma tuzoqlari shundan kelib chiqadi:

flowchart TD
  A[migrations/*.js] --> B[db:migrate]
  B --> C[(SequelizeMeta)]
  C -->|qo'llanganlar o'tkaziladi| B
  D[seeders/*.js] --> E[db:seed:all]
  E -->|sukut: hech qayerga yozilmaydi| F[Har safar hammasi qayta]

Migratsiyalar SequelizeMeta da qayd etiladi, seeder'lar esa sukut bo'yicha — yo'q.

4.1 O'z migratsiyamiz

Generator o'rniga o'zimiz yozgan migratsiya (migrations/20261025100000-jadvallar.js, qisqartirildi):

js
module.exports = {
  async up(queryInterface, Sequelize) {
    await queryInterface.createTable('foydalanuvchilar', {
      id: { type: Sequelize.INTEGER, autoIncrement: true,
        primaryKey: true },
      email: { type: Sequelize.STRING, allowNull: false,
        unique: true },
      toliq_ism: { type: Sequelize.STRING(100),
        allowNull: false },
    });
    await queryInterface.createTable('vazifalar', {
      // … id, matn, bajarildi
      egasi_id: {
        type: Sequelize.INTEGER, allowNull: false,
        references: { model: 'foydalanuvchilar', key: 'id' },
        onDelete: 'CASCADE',
      },
      yaratilgan_vaqt: { type: Sequelize.DATE, allowNull: false,
        defaultValue: Sequelize.fn('now') },
    });
    await queryInterface.addIndex('vazifalar', ['egasi_id']);
  },
  async down(queryInterface) {
    await queryInterface.dropTable('vazifalar');
    await queryInterface.dropTable('foydalanuvchilar');
  },
};

queryInterface — sxema bilan ishlash metodlari: createTable, addColumn, removeColumn, addIndex, changeColumn. Xom SQL ham mumkin: queryInterface.sequelize.query('…').

Qo'llaymiz:

bash
npx sequelize-cli db:migrate:status
npx sequelize-cli db:migrate
text
down 20261025100000-jadvallar.js
== 20261025100000-jadvallar: migrating =======
== 20261025100000-jadvallar: migrated (0.060s)

Holat jadvali — SequelizeMeta, unda faqat fayl nomi:

text
            name             
-----------------------------
 20261025100000-jadvallar.js
(1 row)

db:migrate:undo — oxirgi migratsiyaning down ini bajaradi, db:migrate:undo:all — hammasini.

4.2 Migratsiya yarmida yiqilsa

Sequelize migratsiyani tranzaksiyaga o'raydimi? Sinab ko'ramiz — ikkinchi qadami xato beradigan migratsiya:

js
module.exports = {
  async up(queryInterface, Sequelize) {
    await queryInterface.addColumn('vazifalar', 'muddat',
      { type: Sequelize.DATE });
    await queryInterface.sequelize.query('SELECT 1/0');
  },
  // down …
};
text
== 20261025100200-yarim: migrating =======

ERROR: division by zero

Bazaga qaraymiz: muddat ustuni bor, SequelizeMeta da esa yangi yozuv yo'q. Birinchi qadam qoldi, migratsiya "qo'llanmagan" deb hisoblanadi. Xatoni tuzatib qayta ishga tushirsak:

text
ERROR: column "muddat" of relation "vazifalar" already exists

Endi migratsiya o'zini o'zi to'sib qo'ydi: ustunni qo'lda o'chirish kerak. Bosqichma-bosqich:

Qadam Nima bajarildi Bazada muddat SequelizeMeta da yozuv
1 addColumn paydo bo'ldi yo'q
2 SELECT 1/0 — xato qoldi yo'q
3 qayta db:migrate already exists yo'q

Sabab — sequelize-cli migratsiyani sukut bo'yicha tranzaksiyaga o'ramaydi; har queryInterface chaqiruvi alohida bajariladi. PostgreSQL'da DDL tranzaksiyali bo'lgani uchun buni o'zingiz qilasiz:

js
async up(queryInterface, Sequelize) {
  await queryInterface.sequelize.transaction(async (t) => {
    await queryInterface.addColumn('vazifalar', 'muddat',
      { type: Sequelize.DATE }, { transaction: t });
    // … boshqa qadamlar ham { transaction: t } bilan
  });
},

Har chaqiruvga { transaction: t } berishni unutsangiz — o'sha qadam tranzaksiyadan tashqarida qoladi.

4.3 Seeder

Seeder — boshlang'ich ma'lumot yozadigan fayl. Seed haqida to'liq — Seeding va test ma'lumotlari darsida. Hozir faqat Sequelize'dagi shakli:

js
module.exports = {
  async up(queryInterface) {
    await queryInterface.bulkInsert('foydalanuvchilar', [
      { email: 'ali@example.com', toliq_ism: 'Ali Valiyev' },
      { email: 'malika@example.com',
        toliq_ism: 'Malika Karimova' },
    ]);
  },
  async down(queryInterface) {
    await queryInterface.bulkDelete('foydalanuvchilar', {
      email: ['ali@example.com', 'malika@example.com'],
    });
  },
};

Ikki marta ishga tushiramiz:

bash
npx sequelize-cli db:seed:all
npx sequelize-cli db:seed:all
text
== 20261025100100-namuna: migrated (0.015s)

ERROR: Validation error
ERROR DETAIL: Key (email)=(ali@example.com) already exists.

Ikkinchi safar yiqildi. Sabab: sequelize-cli seeder'larni sukut bo'yicha hech qayerga yozmaydi — SequelizeMeta da faqat migratsiya bor edi. Har db:seed:all hamma seeder'ni qaytadan bajaradi. Ikki yechim: .sequelizerc da seederStorage: "sequelize" (seeder ham holat jadvaliga yoziladi) yoki seeder'ning o'zini qayta ishga tushirishga chidamli qilish (INSERT … ON CONFLICT DO NOTHING). Ikkinchisi — idempotent (necha marta bajarilsa ham natija bir xil) seed, uni Seeding va test ma'lumotlari darsida to'liq ko'ramiz.

5. So'rovlar: CRUD, Op, include

5.1 Ilova kodi

Modellar models/index.js orqali olinadi. Sequelize CommonJS paket, biz esa ESM yozamiz — createRequire bilan (CommonJS va ESM bilan o'zaro ishlash):

js
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
const { Foydalanuvchi, Vazifa, Sequelize, sequelize } =
  require('./models/index.js');
const { Op } = Sequelize;
sequelize.options.logging = (sql) => console.log(sql);

logging — har SQL'ni ko'rsatadi. Sequelize log qatori Executing (default): bilan boshlanadi.

5.2 Yaratish va ommaviy yozish

js
const ali = await Foydalanuvchi.findOne({
  where: { email: 'ali@example.com' } });
await Vazifa.bulkCreate([
  { matn: 'Bozordan non olish', egasi_id: ali.id },
  { matn: 'Hisobot yozish', egasi_id: ali.id,
    bajarildi: true },
  { matn: "Kitob o'qish", egasi_id: ali.id },
]);

Log (bo'lingan):

sql
SELECT "id", "email", "toliq_ism" AS "toliqIsm"
FROM "foydalanuvchilar" AS "Foydalanuvchi"
WHERE "Foydalanuvchi"."email" = 'ali@example.com' LIMIT 1;
INSERT INTO "vazifalar" ("id","matn","bajarildi","egasi_id")
VALUES (DEFAULT,'Bozordan non olish',false,1),
  (DEFAULT,'Hisobot yozish',true,1),
  (DEFAULT,'Kitob o''qish',false,1)
RETURNING "id","matn","bajarildi","yaratilgan_vaqt","egasi_id";

Diqqat qiling: 'ali@example.com' va 'Kitob o''qish' — qiymatlar SQL matni ichida, $1 emas. Sequelize findAll/bulkCreate da qiymatlarni o'zi ekranlab (apostrof ikkilanadi — o''qish) SQL'ga qo'yadi. Bu xavfsiz, chunki ekranlashni kutubxona qiladi. Lekin siz sequelize.query(\… '${x}'`)deb yozsangiz — ekranlash yo'q, bu SQL injection. Xom so'rovda faqatreplacementsyokibind` bilan.

5.3 Hook va validatsiya

Hook (ilgak) — model hayotining ma'lum nuqtasida o'zi chaqiriladigan funksiya: beforeValidate, beforeCreate, afterUpdate, beforeDestroy. Foydalanuvchi modeliga email'ni tozalaydigan hook qo'ydik:

js
hooks: {
  beforeValidate(f) {
    if (typeof f.email === 'string') {
      f.email = f.email.trim().toLowerCase();
    }
  },
},

Sinaymiz — bo'sh joyli, katta harfli email va bo'sh matnli vazifa:

js
const m = await Foydalanuvchi.create({
  email: '  Jasur@Example.COM ', toliqIsm: 'Jasur Aliyev' });
console.log(m.email);
try {
  await Vazifa.create({ matn: '', egasi_id: ali.id });
} catch (e) { console.log(e.name, '|', e.errors[0].message); }
text
jasur@example.com
SequelizeValidationError | Validation len on matn failed

Email tozalandi. Bo'sh matn bazaga umuman bormadi — len validatsiyasi to'xtatdi. Xabarni tarjima qilsak: "matn ustida len validatsiyasi o'tmadi".

Hook'lar qulay, lekin yashirin: kodni o'qiyotgan odam create ichida email o'zgarishini ko'rmaydi. Ommaviy amallarda (bulkCreate, update with where) esa ko'p hook'lar sukut bo'yicha ishlamaydi (individualHooks: true kerak, Sequelize hujjati). Eski loyihada "nega bu email katta harf bilan saqlangan?" savolining javobi ko'pincha shu.

5.4 Op — shart operatorlari

Tenglikdan boshqa shart — Op belgilari bilan:

js
const r = await Vazifa.findAll({
  attributes: ['id', 'matn'],
  where: { bajarildi: false, matn: { [Op.iLike]: '%o%' } },
  order: [['id', 'ASC']], raw: true });
console.log(r);
text
[
  { id: 1, matn: 'Bozordan non olish' },
  { id: 3, matn: "Kitob o'qish" }
]

SQL: WHERE "Vazifa"."bajarildi" = false AND "Vazifa"."matn" ILIKE '%o%'. raw: true — model nusxasi emas, oddiy obyekt qaytaradi (tezroq, kam xotira).

Ko'p ishlatiladigan operatorlar: Op.eq, Op.ne, Op.gt, Op.gte, Op.lt, Op.in, Op.is (IS NULL), Op.like, Op.iLike, Op.or, Op.and. [Op.iLike] — JavaScript'ning hisoblangan kalit sintaksisi ([x]: …), Symbol kalit (Symbol).

5.5 include — bog'langan ma'lumot

js
const f = await Foydalanuvchi.findOne({
  where: { id: ali.id },
  include: [{ model: Vazifa, as: 'vazifalar',
    attributes: ['matn'] }],
});
console.log(JSON.stringify(f));
text
{"id":1,"email":"ali@example.com","toliqIsm":"Ali Valiyev","vazifalar":[{"matn":"Bozordan non olish"},{"matn":"Hisobot yozish"},{"matn":"Kitob o'qish"}]}

Bitta so'rov — LEFT OUTER JOIN "vazifalar" AS "vazifalar" ON "Foydalanuvchi"."id" = "vazifalar"."egasi_id". as: 'vazifalar' — hasMany dagi as bilan bir xil bo'lishi shart, aks holda xato.

Tekshirib ko'ring: Nega findOne bu yerda LIMIT 1 yubormadi, TypeORM esa ikki so'rov yuborgan edi?

Javob

Sequelize where birlamchi kalit bo'yicha ekanini ko'rdi: id = 1 bitta foydalanuvchini beradi, LIMIT kerak emas. LIMIT bo'lmasa, JOIN qatorlarni ko'paytirsa ham muammo yo'q — Sequelize ularni daraxtga yig'adi. Muammo include + limit birga kelganda boshlanadi — keyingi bo'limda.

6. To'rt jim tuzoq

6.1 include + limit

Kanon o'lchovida Sequelize va TypeORM bir xil xatoga uchragan. Biz uni kichik bazada qayta yaratdik: saralash ustuni attributes da yo'q, include va limit bor.

js
await Foydalanuvchi.findAll({
  attributes: ['id'], order: [['email', 'ASC']], limit: 1,
  include: [{ model: Vazifa, as: 'vazifalar' }] });
text
SequelizeDatabaseError | column Foydalanuvchi.email does not exist

Yuborilgan SQL (bo'lingan):

sql
SELECT "Foydalanuvchi".*, "vazifalar"."id" AS "vazifalar.id", …
FROM (SELECT "Foydalanuvchi"."id"
  FROM "foydalanuvchilar" AS "Foydalanuvchi"
  ORDER BY "Foydalanuvchi"."email" ASC LIMIT 1)
  AS "Foydalanuvchi"
LEFT OUTER JOIN "vazifalar" AS "vazifalar" ON …
ORDER BY "Foydalanuvchi"."email" ASC;

LIMIT ni to'g'ri qo'llash uchun Sequelize asosiy jadvalni ichki so'rovga o'radi. Ichki so'rov faqat id ni oladi (biz shuni so'radik). Tashqi ORDER BY esa email ga ishora qiladi — u ichki so'rovda yo'q. Tarjimasi: "Foydalanuvchi.email ustuni mavjud emas". Tuzatish: saralash ustunini attributes ga qo'shing (kanon ham shunday tuzatgan).

6.2 sync({ alter: true })

Sequelize'da ham TypeORM'dagi synchronize ning egizagi bor — sequelize.sync(). sync({ force: true }) jadvallarni o'chirib qayta yaratadi. sync({ alter: true }) — "modelga moslashtir". Biz uni muddat ustuni qolgan (yarim migratsiyadan) va ma'lumot to'ldirilgan bazada ishga tushirdik. Muhim qatorlar:

text
Executing (default): ALTER TABLE "vazifalar" DROP CONSTRAINT "vazifalar_egasi_id_fkey"
Executing (default): ALTER TABLE "vazifalar"  ADD FOREIGN KEY ("egasi_id") REFERENCES "foydalanuvchilar" ("id") ON DELETE SET NULL ON UPDATE CASCADE;
Executing (default): ALTER TABLE "vazifalar" ALTER COLUMN "yaratilgan_vaqt" DROP NOT NULL;ALTER TABLE "vazifalar" ALTER COLUMN "yaratilgan_vaqt" DROP DEFAULT; …
Executing (default): ALTER TABLE "public"."vazifalar" DROP COLUMN "muddat";

Keyin \d vazifalar:

text
 yaratilgan_vaqt | timestamp with time zone |           |          | 
Foreign-key constraints:
    "vazifalar_egasi_id_fkey" FOREIGN KEY (egasi_id) REFERENCES foydalanuvchilar(id) ON UPDATE CASCADE ON DELETE SET NULL

Bir buyruqda to'rtta zarar:

  1. muddat o'chdi — ma'lumoti bilan. Modelda yo'q edi, demak "ortiqcha".
  2. ON DELETE CASCADE → SET NULL. Modeldagi belongsTo da onDelete yozilmagan — Sequelize o'z sukutini qo'ydi. Endi foydalanuvchini o'chirish… egasi_id NOT NULL bo'lgani uchun xato beradi. Migratsiyadagi qaror jim bekor bo'ldi.
  3. yaratilgan_vaqt ning DEFAULT now() va NOT NULL i olib tashlandi — modelda ular yo'q edi.
  4. Hech qanday savol, ogohlantirish yo'q.

Diqqat: sync() ni (ayniqsa alter va force bilan) faqat tashlab yuboriladigan bazada ishlating. Model — bazaning to'liq tavsifi emas: default'lar, cheklovlar, trigger'lar migratsiyada yashaydi. sync esa modelni "haqiqat" deb, bazani unga moslashtiradi.

6.3 Pluralizatsiya va seeder

Yuqorida ko'rdik: Vazifas va takroriy seeder xatosi. Ikkisi ham "jim" — birinchi kuni ishlaydi, keyin muammo beradi.

7. Ko'p uchraydigan xatolar

1. SequelizeEagerLoadingError. Biz association'ni as siz yozib, include da as: 'vazifalar' berdik:

text
SequelizeEagerLoadingError | Vazifa is associated to Foydalanuvchi using an alias. You've included an alias (vazifalar), but it does not match the alias(es) defined in your association (Vazifas).

Tarjimasi: "Vazifa Foydalanuvchi bilan taxallus orqali bog'langan. Siz vazifalar taxallusini berdingiz, lekin u association'dagi (Vazifas) bilan mos emas". as siz association taxallusi yana inglizcha ko'plik bo'ldi. Tuzatish: ikkala joyda bir xil as.

2. relation "Vazifas" does not exist. Model tableName siz, bazada esa vazifalar. Tuzatish: tableName va timestamps: false (yoki freezeTableName: true).

3. column "createdAt" does not exist. timestamps sukut bo'yicha yoqiq — Sequelize createdAt/updatedAt ni kutadi. Tuzatish: timestamps: false yoki shu ustunlarni migratsiyaga qo'shish.

4. column X does not exist + include + limit. Saralash ustuni attributes da yo'q. Tuzatish: qo'shing yoki subQuery: false (lekin u holda LIMIT qatorlarga emas, JOIN natijasiga qo'llanadi — ehtiyot bo'ling).

5. Yarim qolgan migratsiya. already exists xatosi. Tuzatish: qo'lda tozalash va kelajakda queryInterface.sequelize.transaction(…).

6. config.json da parol. Tuzatish: use_env_variable, va Git tarixidan sirni o'chirgandan keyin parolni almashtirish (Sirlarni boshqarish).

8. Mashqlar

SQL mashq yechimi tekshirilgan (biz ishga tushirdik, PostgreSQL 17.6).

1-mashq (oson)

Eski loyihada Foydalanuvchi.hasMany(Vazifa) yozilgan, as va foreignKey yo'q. Sequelize tashqi kalit ustunini qanday nomlaydi va bazada sizning ustuningiz egasi_id bo'lsa nima bo'ladi?

Yechim

Sukut bo'yicha Sequelize model nomidan + Id qiladi: FoydalanuvchiId. Bazada bunday ustun yo'q — biz sinab ko'rdik — birinchi include da column Vazifas.FoydalanuvchiId does not exist chiqdi (taxallus ham inglizcha ko'plik: Vazifas). Tuzatish: hasMany(Vazifa, { foreignKey: 'egasi_id', as: 'vazifalar' }) va teskari tomonda belongsTo(…, { foreignKey: 'egasi_id', as: 'egasi' }) — ikkala tomonda bir xil foreignKey.

2-mashq (o'rta)

Quyidagi Sequelize so'rovi qanday SQL yuboradi? WHERE qismini yozing va bazada natijasini toping (vazifalar jadvali — o'zingiz yarating):

js
await Vazifa.findAll({
  attributes: ['matn'],
  where: {
    [Op.or]: [
      { bajarildi: true },
      { matn: { [Op.iLike]: 'kitob%' } },
    ],
    id: { [Op.gt]: 1 },
  },
  order: [['id', 'ASC']], raw: true,
});

Ishora: obyektdagi kalitlar AND bilan birlashadi, [Op.or] massivi ichidagilar — OR bilan. ILIKE — registrga befarq LIKE (SELECT va WHERE).

Yechim

WHERE ("bajarildi" = true OR "matn" ILIKE 'kitob%') AND "id" > 1. Sinash:

sql
CREATE TABLE vazifalar (id serial PRIMARY KEY,
  matn text NOT NULL, bajarildi boolean NOT NULL DEFAULT false);
INSERT INTO vazifalar (matn, bajarildi) VALUES
  ('Kitob sotib olish', true), ('Hisobot yozish', true),
  ('kitob o''qish', false), ('Non olish', false);
SELECT matn FROM vazifalar
WHERE (bajarildi = true OR matn ILIKE 'kitob%') AND id > 1
ORDER BY id ASC;
text
CREATE TABLE
INSERT 0 4
      matn      
----------------
 Hisobot yozish
 kitob o'qish
(2 rows)

1-qator (Kitob sotib olish) ikkala shartga mos, lekin id > 1 uni chiqarib tashladi. kitob o'qish — kichik harf bilan, ILIKE uni topdi. Qavslar muhim: ular bo'lmasa, AND OR dan kuchli bo'lgani uchun ma'no o'zgarardi.

3-mashq (qiyin)

«Seeder» bo'limidagi seeder'ni qayta ishga tushirishga chidamli (idempotent) qiling: ikkinchi db:seed:all xato bermasin va dublikat yaratmasin. queryInterface.bulkInsert ning ignoreDuplicates imkoniyatidan yoki xom SQL'dan foydalaning. Natijani SQL'da tekshiring.

Yechim
js
module.exports = {
  async up(queryInterface) {
    await queryInterface.sequelize.query(`
      INSERT INTO foydalanuvchilar (email, toliq_ism) VALUES
        ('ali@example.com', 'Ali Valiyev'),
        ('malika@example.com', 'Malika Karimova')
      ON CONFLICT (email) DO NOTHING`);
  },
  // down — o'zgarmaydi
};

ON CONFLICT (email) DO NOTHING — noyob kalit to'qnashsa, qator jim o'tkaziladi (UPSERT va MERGE). bulkInsert(…, { ignoreDuplicates: true }) PostgreSQL'da ON CONFLICT DO NOTHING (ustunsiz — har qanday noyoblik to'qnashuvida) yasaydi; biz log'da ko'rdik. Ikki marta bajarib tekshiramiz:

sql
CREATE TABLE foydalanuvchilar (id serial PRIMARY KEY,
  email varchar NOT NULL UNIQUE,
  toliq_ism varchar(100) NOT NULL);
INSERT INTO foydalanuvchilar (email, toliq_ism) VALUES
  ('ali@example.com', 'Ali Valiyev'),
  ('malika@example.com', 'Malika Karimova')
ON CONFLICT (email) DO NOTHING;
INSERT INTO foydalanuvchilar (email, toliq_ism) VALUES
  ('ali@example.com', 'Ali Valiyev'),
  ('malika@example.com', 'Malika Karimova')
ON CONFLICT (email) DO NOTHING;
SELECT count(*) FROM foydalanuvchilar;
text
CREATE TABLE
INSERT 0 2
INSERT 0 0
 count 
-------
     2
(1 row)

Ikkinchi INSERT — 0 0: hech narsa qo'shilmadi, xato ham yo'q. Bu yerda id serial'i baribir 2 ga "yeyiladi" — UPSERT darsidagi tafsilot.

9. Loyiha qadami

vazifalar-api ga o'zgarish yo'q — kanon qarori: Sequelize eski loyihalarda uchraydi, yangi loyihaga tavsiya etilmaydi. Kanon o'lchovi katta bazasida (500 000 vazifa, mediana 30). Ro'yxat 50 — 1.17 ms (pg 1.00), vazifa + izohlar — 2.03 ms, 1 SQL (pg 1.34), yozish — 3.02 ms (pg 2.41); paket 3.5 MB, 16 bevosita bog'liqlik. Ya'ni tezlik muammo emas. Muammo — yuqoridagi jim tuzoqlar va TypeScript turlarining zaifligi (require qilingan model any ga yaqin).

Tajriba qilmoqchi bo'lsangiz — alohida papkada: npx sequelize-cli init, use_env_variable, bitta migratsiya, db:migrate, db:migrate:undo. vazifalar-api ga commit yo'q.

10. Real ishda

  • Eski Express loyihalari. Birinchi hafta ro'yxati: config.json da parol bormi? sync() qayerda chaqiriladi (ayniqsa app.listen dan oldin)? Seeder'lar holati qayerda saqlanadi?
  • Sequelize 7. Yillardan beri alpha holatida (yangi @sequelize/core paketi, TypeScript'ga yaqinroq). 2026-10 holatida barqaror reliz sequelize 6.37.8 — npm view bo'yicha. Yangi loyihada 7 ga tayanmang.
  • Ko'chish. Sequelize'dan Prisma yoki Drizzle'ga o'tish odatda bosqichma-bosqich: avval db pull bilan mavjud bazadan sxema olinadi, yangi kod yangi kutubxonada yoziladi, eski kod asta-sekin almashadi (Prisma 7: o'rnatish).
  • Intervyuda: "include qanday SQL beradi?", "sync va migratsiya farqi?", "hook'lar qachon ishlamaydi?".

Xulosa

  • Sequelize — CommonJS uslubidagi eski, keng tarqalgan ORM: define/Model.init, hasMany/belongsTo, include, Op.
  • sequelize-cli: init, model:generate, db:migrate, db:migrate:undo, db:seed:all; holat — SequelizeMeta.
  • Generator Vazifa ni Vazifas qiladi — tableName ni aniq bering; config.json ga parol yozmang — use_env_variable.
  • Migratsiya sukut bo'yicha tranzaksiyasiz: yarmida yiqilsa, birinchi qadam qoladi va qayta urinish already exists bilan to'xtaydi.
  • Seeder'lar sukut bo'yicha qayd etilmaydi — ikkinchi ishga tushirish yiqildi; idempotent seed yozing.
  • sync({ alter: true }) ustunni o'chirdi, CASCADE ni SET NULL ga, default'larni yo'q qildi — faqat tashlab yuboriladigan bazada.

Keyingi dars: ORM tanlash qo'llanmasi — Prisma, Drizzle, Kysely, Knex, TypeORM va Sequelize'ni o'lchov bilan solishtirib, loyiha turiga qarab tanlash.

Manbalar

  • Sequelize v6 hujjati — Model Basics, Associations, Eager Loading, Hooks, Migrations: https://sequelize.org/docs/v6/
  • sequelize-cli README (seederStorage, use_env_variable): https://github.com/sequelize/cli
  • IlmHamroh kanon o'lchovi t29-orm (PostgreSQL 18.6, 2026-10-25); darsdagi Sequelize chiqishlari — biz ishga tushirdik (Sequelize 6.37.8, sequelize-cli 6.6.5, PostgreSQL 17.6, Windows 11), 2026-10-25.
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Sequelize: model, associations, include, Op va sequelize-cli migratsiyalari — IlmHamroh