Mundarija (32)
- Bu darsda
- 1. Nega bu kerak?
- 2. Loyiha tuzilmasi: sequelize-cli init
- 2.1 init
- 2.2 config.json — birinchi tuzoq
- 3. Model: define va Model.init
- 3.1 Generator va pluralizatsiya
- 3.2 Model.init — klass shakli
- 3.3 define — funksiya shakli
- 4. Migratsiya va seeder
- 4.1 O'z migratsiyamiz
- 4.2 Migratsiya yarmida yiqilsa
- 4.3 Seeder
- 5. So'rovlar: CRUD, Op, include
- 5.1 Ilova kodi
- 5.2 Yaratish va ommaviy yozish
- 5.3 Hook va validatsiya
- 5.4 Op — shart operatorlari
- 5.5 include — bog'langan ma'lumot
- 6. To'rt jim tuzoq
- 6.1 include + limit
- 6.2 sync({ alter: true })
- 6.3 Pluralizatsiya va seeder
- 7. Ko'p uchraydigan xatolar
- 8. Mashqlar
- 1-mashq (oson)
- 2-mashq (o'rta)
- 3-mashq (qiyin)
- 9. Loyiha qadami
- 10. Real ishda
- Xulosa
- Manbalar
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()yokiModel.init()bilan yoziladi, bog'lanishlar —hasMany/belongsTo, bog'langan ma'lumot —include, shartlar —Opoperatorlari. Migratsiya va seed —sequelize-cli. Biz o'lchagan tuzoqlar: CLI o'zbekchaVazifaniVazifasqiladi, seeder takroriy ishga tushsa yiqiladi,sync({ alter: true })ustunni o'chirdi vaON DELETE CASCADEni jimSET NULLga almashtirdi.
Bu darsda
- Sequelize modelini
definevaModel.initshakllarida o'qiy va yoza olasiz. hasMany/belongsTo,includevaOpbilan so'rovlar yozasiz.- Validatsiya va hook'lar (
beforeValidate) qanday ishlashini bilasiz. sequelize-clibilan 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,
pg8.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:
npm i sequelize@6.37.8 pg@8.23.1
npm i -D sequelize-cli@6.6.5
npx sequelize-cli initSequelize 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:
{
"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:
{
"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:
npx sequelize-cli model:generate --name Vazifa \
--attributes matn:text,bajarildi:boolean,egasiId:integerYaratilgan migratsiya (boshi):
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):
'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/updatedAtni kutmaydi (bizda o'zyaratilgan_vaqtbor).field: 'yaratilgan_vaqt'— JS'dayaratilganVaqt, bazadayaratilgan_vaqt(TypeORM'daginame, Prisma'dagi@map).validate: { len: [1, 100] }— JS tomonidagi tekshiruv, bazaga borishdan oldin.static associate(models)— bog'lanishlar; unimodels/index.jshamma 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):
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. BazadagiCHECKcheklovi 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):
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:
npx sequelize-cli db:migrate:status
npx sequelize-cli db:migratedown 20261025100000-jadvallar.js
== 20261025100000-jadvallar: migrating =======
== 20261025100000-jadvallar: migrated (0.060s)Holat jadvali — SequelizeMeta, unda faqat fayl nomi:
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:
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.addColumn('vazifalar', 'muddat',
{ type: Sequelize.DATE });
await queryInterface.sequelize.query('SELECT 1/0');
},
// down …
};== 20261025100200-yarim: migrating =======
ERROR: division by zeroBazaga qaraymiz: muddat ustuni bor, SequelizeMeta da esa yangi yozuv yo'q. Birinchi qadam qoldi, migratsiya "qo'llanmagan" deb hisoblanadi. Xatoni tuzatib qayta ishga tushirsak:
ERROR: column "muddat" of relation "vazifalar" already existsEndi 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:
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:
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:
npx sequelize-cli db:seed:all
npx sequelize-cli db:seed:all== 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):
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
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):
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:
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:
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); }jasur@example.com
SequelizeValidationError | Validation len on matn failedEmail 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:
const r = await Vazifa.findAll({
attributes: ['id', 'matn'],
where: { bajarildi: false, matn: { [Op.iLike]: '%o%' } },
order: [['id', 'ASC']], raw: true });
console.log(r);[
{ 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
const f = await Foydalanuvchi.findOne({
where: { id: ali.id },
include: [{ model: Vazifa, as: 'vazifalar',
attributes: ['matn'] }],
});
console.log(JSON.stringify(f));{"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
findOnebu yerdaLIMIT 1yubormadi, 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.
await Foydalanuvchi.findAll({
attributes: ['id'], order: [['email', 'ASC']], limit: 1,
include: [{ model: Vazifa, as: 'vazifalar' }] });SequelizeDatabaseError | column Foydalanuvchi.email does not existYuborilgan SQL (bo'lingan):
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:
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:
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 NULLBir buyruqda to'rtta zarar:
muddato'chdi — ma'lumoti bilan. Modelda yo'q edi, demak "ortiqcha".ON DELETE CASCADE→SET NULL. ModeldagibelongsTodaonDeleteyozilmagan — Sequelize o'z sukutini qo'ydi. Endi foydalanuvchini o'chirish…egasi_idNOT NULLbo'lgani uchun xato beradi. Migratsiyadagi qaror jim bekor bo'ldi.yaratilgan_vaqtningDEFAULT now()vaNOT NULLi olib tashlandi — modelda ular yo'q edi.- Hech qanday savol, ogohlantirish yo'q.
Diqqat:
sync()ni (ayniqsaaltervaforcebilan) faqat tashlab yuboriladigan bazada ishlating. Model — bazaning to'liq tavsifi emas: default'lar, cheklovlar, trigger'lar migratsiyada yashaydi.syncesa 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:
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):
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:
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;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
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:
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;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.jsonda parol bormi?sync()qayerda chaqiriladi (ayniqsaapp.listendan oldin)? Seeder'lar holati qayerda saqlanadi? - Sequelize 7. Yillardan beri alpha holatida (yangi
@sequelize/corepaketi, TypeScript'ga yaqinroq). 2026-10 holatida barqaror relizsequelize6.37.8 —npm viewbo'yicha. Yangi loyihada 7 ga tayanmang. - Ko'chish. Sequelize'dan Prisma yoki Drizzle'ga o'tish odatda bosqichma-bosqich: avval
db pullbilan mavjud bazadan sxema olinadi, yangi kod yangi kutubxonada yoziladi, eski kod asta-sekin almashadi (Prisma 7: o'rnatish). - Intervyuda: "
includeqanday SQL beradi?", "syncva 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
VazifaniVazifasqiladi —tableNameni aniq bering;config.jsonga parol yozmang —use_env_variable. - Migratsiya sukut bo'yicha tranzaksiyasiz: yarmida yiqilsa, birinchi qadam qoladi va qayta urinish
already existsbilan to'xtaydi. - Seeder'lar sukut bo'yicha qayd etilmaydi — ikkinchi ishga tushirish yiqildi; idempotent seed yozing.
sync({ alter: true })ustunni o'chirdi,CASCADEniSET NULLga, 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.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!