WisarWisar
Dasturlash kitobi/6-QISM — Database21 daqiqa

6.11-bob: ORM — Sequelize (model, relations, migration)

6-QISM — Ma'lumotlar bazasi (Database) · 11-mavzu


1. Kirish va motivatsiya

Xom SQL'ni (6.4–6.10) chuqur o'rgandik — bu poydevor. Endi ORM (Object-Relational Mapping) ga o'tamiz: SQL'ni JavaScript obyektlari bilan ishlash. ORM — relatsion DB jadvallari va qatorlarini JS class va obyektlariga moslashtiruvchi qatlam. SQL yozish o'rniga, User.findByPk(1) deysiz — ORM uni SQL'ga aylantiradi, bajaradi, va natijani JS obyekti qilib qaytaradi. Bu — produktivlikni keskin oshiradi.

Sizning stack'ingizda uchta ORM bor: Sequelize (klassik, keng tarqalgan — bu bob), Prisma (zamonaviy, type-safe — 6.12), TypeORM (NestJS bilan mashhur — 6.13). Sequelize — eng qadimiy va keng ishlatiladigani; ko'p mavjud loyihada bor. U MySQL, PostgreSQL, SQLite, SQL Server bilan ishlaydi (DB'ni almashtirsangiz, kod deyarli o'zgarmaydi — abstraksiya).

Muhim: ORM SQL'ni almashtirmaydi — uning ustida ishlaydi. Shuning uchun biz avval SQL'ni o'rgandik (6.4-6.10). ORM qulay, lekin u ham SQL generatsiya qiladi; N+1 (6.10: 2.11), indeks, tranzaksiya — bularning hammasi ORM'da ham bor. SQL'ni bilmasdan ORM ishlatish — "qora quti"ga ishonish (sekin so'rov, xato — tushunmaysiz). Bu bob: Sequelize bilan model, bog'lanishlar (associations), so'rovlar, tranzaksiya, migration va seeding — chuqur.

O'xshatish: xom SQL — xorijiy tilda gaplashish (DB tilini bevosita bilasiz — kuchli, lekin har gapni o'zingiz tuzasiz). ORM — tarjimon orqali gaplashish: siz ona tilingizda (JS) aytasiz, tarjimon (ORM) DB tiliga (SQL) o'giradi. Tez, qulay — lekin tarjimon ba'zan noqulay so'zlaydi (sekin SQL). Yaxshi natija uchun ikkala tilni ham bilish kerak (SQL + ORM).

Nega muhim?

  • Produktivlik — SQL yozish o'rniga JS obyektlari (tez yozish).
  • Stack talabi — Sequelize/Prisma/TypeORM uchchovi ham sizning stack'ingizda.
  • DB abstraksiyasi — DB'ni almashtirish oson (MySQL PostgreSQL).
  • Migration — schema o'zgarishini nazorat ostida boshqarish.

2. Nazariya — chuqur tushuntirish

2.1. ORM nima va nega (under the hood)

ORM — DB jadvallarini obyektlarga moslaydi (sequelize.org):

text
  Jadval (users)    Model (User class)
  Qator (row)       Instance (obyekt)
  Ustun (column)    Property (xususiyat)

  Siz yozasiz:  await User.findByPk(1)
  ORM qiladi:   SELECT * FROM users WHERE id = 1   JS obyekt qaytaradi

ORM ishi: sizning JS chaqiruvingizni SQL'ga aylantiradi, bajaradi, natijani obyektga o'giradi. Siz SQL ko'rmaysiz (lekin u bor!). Foydasi: tezroq yozasiz, DB-agnostik, xavfsiz (parametrli — 6.4: 2.15 avtomatik). Kamchiligi: yashirin SQL (sekin bo'lishi mumkin — 2.14).

2.2. ORM afzalliklari va kamchiliklari

text
   Afzallik:
  - Tez yozish (SQL o'rniga JS)
  - DB-agnostik (MySQL  PostgreSQL almashtirish oson)
  - Xavfsiz (parametrli so'rov avtomatik — injection himoyasi — 14)
  - Migration, validatsiya, hook, bog'lanish — tayyor
  - Type-safety (Prisma/TypeORM — TS bilan)

   Kamchilik:
  - Yashirin SQL (sekin so'rov — N+1 — 2.14)
  - Murakkab so'rov qiyin (window/CTE — ko'pincha xom SQL — 6.7)
  - O'rganish (ORM API + baribir SQL bilim kerak)
  - "Sehrli" xatti-harakat (debug qiyin)

Konsensus: ORM kundalik CRUD uchun a'lo (tez, xavfsiz). Murakkab analitik so'rov uchun — xom SQL 6.7-bob yoki query builder. SQL bilimi shart (ORM uni yashiradi, lekin yo'qotmaydi).

2.3. Sequelize o'rnatish va ulanish

bash
npm install sequelize          # ORM
npm install pg pg-hstore        # PostgreSQL driver (yoki mysql2 — MySQL)
js
import { Sequelize } from "sequelize";

const sequelize = new Sequelize(process.env.DATABASE_URL, {   // (5.8)
  dialect: "postgres",                         // yoki "mysql"
  logging: false,                              // SQL log (dev'da true — SQL ko'rish)
  pool: { max: 10, idle: 30000 },              // connection pool (6.5: 2.5)
});

await sequelize.authenticate();                // ulanishni tekshirish

dialect — qaysi DB (postgres/mysql/sqlite). Sequelize shu DB'ning driver'ini ishlatadi. logging: true (dev) — generatsiya qilingan SQL'ni ko'rsatadi (ORM nima qilayotganini tushunish uchun muhim — 2.14). pool — connection pool 6.5-bob.

2.4. Model ta'rifi (jadval)

Model — jadvalni ifodalovchi class (sequelize.org):

js
import { DataTypes } from "sequelize";

const User = sequelize.define("User", {          // "User"  "Users" jadval
  id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
  ism: { type: DataTypes.STRING, allowNull: false },          // NOT NULL (6.4)
  email: { type: DataTypes.STRING, unique: true, allowNull: false, validate: { isEmail: true } },
  yosh: { type: DataTypes.INTEGER, validate: { min: 18 } },   // validatsiya (2.6)
  rol: { type: DataTypes.ENUM("user", "admin"), defaultValue: "user" },
}, {
  timestamps: true,                              // createdAt, updatedAt avtomatik (6.2)
  // tableName: "users",  paranoid: true (soft delete)
});

DataTypes — SQL turlari (STRINGVARCHAR, INTEGER, BOOLEAN, DATE, ENUM, JSONB — 6.4: 2.3). Har maydonga: tur + cheklovlar (allowNull, unique, defaultValue) + validate 2.6-bob. timestamps — createdAt/updatedAt avtomatik. Model nomi jadval (ko'plik).

Ikki uslub: yuqoridagi sequelize.define(...) — funksional (qisqa, keng tarqalgan). Muqobil — class-based: class User extends Model {} va so'ng User.init({...maydonlar}, { sequelize, modelName: "User" }). Ikkisi ham bir xil natija beradi; init uslubi TypeScript va model'ga maxsus metod qo'shishda qulayroq 2.13-bob. Bu bobda define uslubidan foydalanamiz.

2.5. CRUD (model metodlari)

js
// CREATE
const user = await User.create({ ism: "Ali", email: "ali@a.uz" });

// READ
await User.findAll();                            // hammasi (SELECT *)
await User.findByPk(1);                          // PK bo'yicha (WHERE id=1)
await User.findOne({ where: { email: "ali@a.uz" } });   // shartli
await User.findAll({ where: { yosh: { [Op.gt]: 18 } } });   // operator (2.7)

// UPDATE
await user.update({ yosh: 26 });                 // instance
await User.update({ yosh: 26 }, { where: { id: 1 } });   // to'g'ridan

// DELETE
await user.destroy();                            // instance
await User.destroy({ where: { id: 1 } });        // to'g'ridan

Sequelize ikki uslub: instance (user.update) va static (User.update({...}, {where})). findByPk (PK), findOne (bitta), findAll (ko'p). MongoDB 6.2-bob bilan o'xshash, lekin SQL ustida.

2.6. Validatsiya va hook

js
const User = sequelize.define("User", {
  email: { type: DataTypes.STRING, validate: { isEmail: true } },      // built-in
  parol: { type: DataTypes.STRING, validate: { len: [8, 100] } },      // uzunlik
}, {
  hooks: {
    beforeCreate: async (user) => {              // saqlashdan oldin (6.2: 2.16)
      user.parol = await bcrypt.hash(user.parol, 12);   // parol hash (5.15)
    },
  },
});

Validatsiya (5.9, 6.2: 2.5 — DB darajasida): isEmail, len, min/max, notEmpty, custom. Hook (lifecycle): beforeCreate, afterUpdate — parol hash, slug. Mongoose'dagi 6.2-bob ekvivalent.

2.7. Operatorlar (Op)

js
import { Op } from "sequelize";

await User.findAll({
  where: {
    yosh: { [Op.gt]: 18 },                       // > 18
    rol: { [Op.in]: ["admin", "moderator"] },    // IN
    ism: { [Op.like]: "Al%" },                   // LIKE
    [Op.or]: [{ vip: true }, { yosh: { [Op.gte]: 60 } }],   // OR
  },
  order: [["yosh", "DESC"]],                      // ORDER BY (6.4: 2.10)
  limit: 10, offset: 20,                          // sahifalash
  attributes: ["ism", "email"],                   // SELECT ustunlar (6.4)
});

Op — SQL operatorlari (Op.gt, Op.in, Op.like, Op.or — 6.4: 2.9). MongoDB query operatorlariga (6.2: 2.8) o'xshash. order/limit/offset/attributes — so'rovni sozlash.

2.8. Associations (bog'lanishlar) — eng muhim

Sequelize bog'lanishlari (sequelize.org):

text
  One-to-One:   hasOne + belongsTo
  One-to-Many:  hasMany + belongsTo
  Many-to-Many: belongsToMany (ikki tomondan, junction jadval)
js
// One-to-Many: User  ko'p Order (6.1: 2.5)
User.hasMany(Order, { foreignKey: "userId" });   // user'ning ko'p buyurtmasi
Order.belongsTo(User, { foreignKey: "userId" }); // buyurtma bir user'niki

Ikki tomonlama ta'rif: hasMany (user tomoni) + belongsTo (order tomoni) — birga. Sequelize FK (userId) ni avtomatik yaratadi/ishlatadi (6.1: 2.5). Bu — bog'lanishning asosi; keyin include bilan birga olinadi 2.9-bob.

2.9. Eager loading (include — JOIN)

Include — bog'langan ma'lumotni birga olish (JOIN — 6.7, MongoDB populate — 6.2: 2.13):

js
// User + uning buyurtmalari (bitta so'rovda — JOIN)
const user = await User.findByPk(1, {
  include: [{ model: Order }],                   // buyurtmalarni ham (eager)
});
console.log(user.Orders);                        // buyurtmalar massivi

// Nested include + shart
await User.findAll({
  include: [{
    model: Order,
    where: { holat: "tugallandi" },              // faqat tugallangan buyurtmalar
    include: [{ model: Product }],               // ichma-ich (buyurtma  mahsulot)
  }],
});

include = JOIN (eager loading): bog'langan ma'lumotni bitta so'rovda oladi (N+1 oldini oladi — 2.14, 6.10: 2.11). Lekin ortiqcha include — murakkab, sekin so'rov (manba). Faqat kerakli ma'lumotni include qiling.

2.10. Tranzaksiya

js
const t = await sequelize.transaction();         // tranzaksiya (6.5: 2.9, 6.9)
try {
  await Account.update({ balans: ... }, { where: { id: 1 }, transaction: t });   // t!
  await Account.update({ balans: ... }, { where: { id: 2 }, transaction: t });
  await t.commit();                              // saqla
} catch (err) {
  await t.rollback();                            // bekor
  throw err;
}

// Managed transaction (avtomatik commit/rollback — afzal)
await sequelize.transaction(async (t) => {
  await Account.update({...}, { transaction: t });
  await Account.update({...}, { transaction: t });
  // xato bo'lsa — avtomatik rollback; muvaffaqiyat — commit
});

Har amalga { transaction: t } bering (aks holda tranzaksiyadan tashqarida — 6.9: 2.9). Managed transaction (callback) — afzal: commit/rollback avtomatik (unutilmaydi). Tranzaksiya — pul, ko'p yozuv (6.9 ACID).

2.11. Migration (schema o'zgarishini nazorat)

Migration — DB schema o'zgarishini versiyalangan, qaytariladigan fayllar bilan boshqarish (sequelize-cli):

text
  Migration nima uchun:
  - Schema o'zgarishi (jadval/ustun qo'shish) NAZORAT ostida (git'da — 4)
  - Jamoa/muhitlar SINXRON (har kim bir xil schema)
  - QAYTARILADIGAN (up — qo'llash; down — bekor qilish)
  - Production'da xavfsiz (qo'lda ALTER emas — 6.4: 2.13)
js
// migrations/xxxx-create-users.js
export async function up(queryInterface, Sequelize) {
  await queryInterface.createTable("Users", {     // jadval yaratish
    id: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true },
    ism: { type: Sequelize.STRING, allowNull: false },
    createdAt: Sequelize.DATE, updatedAt: Sequelize.DATE,
  });
}
export async function down(queryInterface) {
  await queryInterface.dropTable("Users");        // bekor qilish (qaytarish)
}

Migration MAJBURIY (production — manba): schema'ni qo'lda o'zgartirmang (6.4: 2.13). Har o'zgarish — migration fayl (git'da — 4, versiyalangan). up (qo'llash), down (qaytarish). sequelize-cli bilan boshqariladi (db:migrate, db:migrate:undo). Bu — jamoa va muhitlarni sinxron tutadi.

2.12. Seeding (boshlang'ich ma'lumot)

Seed — DB'ga boshlang'ich/test ma'lumot solish (sequelize):

js
// seeders/xxxx-demo-users.js
export async function up(queryInterface) {
  await queryInterface.bulkInsert("Users", [
    { ism: "Admin", email: "admin@a.uz", createdAt: new Date(), updatedAt: new Date() },
    { ism: "Test", email: "test@a.uz", createdAt: new Date(), updatedAt: new Date() },
  ]);
}
export async function down(queryInterface) {
  await queryInterface.bulkDelete("Users", null, {});
}

Seed — boshlang'ich ma'lumot (admin foydalanuvchi, kategoriyalar, test ma'lumoti). Dev/test uchun qulay (db:seed:all). Migration'dan farqi: migration — tuzilma; seed — ma'lumot.

2.13. Model fayllar tuzilishi (loyiha)

text
  models/
    index.js       — sequelize ulanish + barcha modellarni yuklash
    user.js        — User model + associate (bog'lanishlar)
    order.js       — Order model
  migrations/      — schema o'zgarishlari
  seeders/         — boshlang'ich ma'lumot
  config/          — DB sozlamalari (dev/test/prod)

Sequelize loyihasi shu tuzilmada (sequelize-cli generatsiya qiladi). models/index.js — markaziy (ulanish + modellar + associate). Migration/seed — alohida papka.

2.14. ORM tuzog'i — N+1 va yashirin SQL

ORM'ning eng katta tuzog'i — N+1 (6.10: 2.11) va yashirin sekin SQL:

js
//  N+1 (har user uchun alohida so'rov!)
const users = await User.findAll();              // 1 so'rov
for (const u of users) {
  const orders = await u.getOrders();            // har user uchun (N so'rov!)
}

//  Eager loading (include — 1 so'rov — 2.9)
const users = await User.findAll({ include: [Order] });   // JOIN

ORM N+1'ni yashiradi (ko'rinmaydi, lekin sekin): tsiklda lazy loading (getOrders) — N+1. include (eager) bilan oldini oling. logging: true 2.3-bob bilan generatsiya qilingan SQL'ni ko'ring (necha so'rov?). SQL bilimi 6.10-bob shu yerda kerak.

2.15. Raw query (murakkab so'rov)

ORM murakkab so'rovni (window/CTE — 6.7) qiyin ifodalaydi xom SQL:

js
// Murakkab so'rov — raw query (parametrli — 14)
const [natija] = await sequelize.query(
  "SELECT u.ism, RANK() OVER (ORDER BY SUM(o.summa) DESC) AS reyting FROM ...",
  { replacements: { sana: "2026-01-01" }, type: QueryTypes.SELECT }   // parametrli
);

ORM hamma narsani qila olmaydi (window functions, murakkab CTE — 6.7). Bunday holatda sequelize.query (xom SQL) — parametrli (replacements — injection himoyasi — 14). ORM + xom SQL aralash — normal amaliyot.

2.16. Xavfsizlik va best practices (14)

text
   Migration har doim (qo'lda ALTER emas — 2.11, 14)
   Tranzaksiya ko'p yozuvda (managed — 2.10)
   Eager loading (include) o'ylab — N+1 oldini oling, lekin ortiqcha emas (2.9, 2.14)
   logging: true (dev) — SQL'ni ko'rib tekshiring (2.3, 2.14)
   Validatsiya (model + API — 5.9); hook (parol hash — 2.6)
   Raw query parametrli (replacements — 14, 2.15)
   Maxfiy maydon (parol) — defaultScope: attributes exclude
   Indeks (model'da indexes; migration'da — 6.10)

3. Sintaksis — tez ma'lumotnoma

js
import { Sequelize, DataTypes, Op } from "sequelize";
const sequelize = new Sequelize(url, { dialect: "postgres" });   // (2.3)

const User = sequelize.define("User", { ism: DataTypes.STRING }, { timestamps: true });   // (2.4)

// CRUD (2.5)
await User.create({...});  await User.findByPk(1);  await User.findAll({ where: {...} });
await user.update({...});  await user.destroy();

// Associations (2.8)
User.hasMany(Order); Order.belongsTo(User);
await User.findByPk(1, { include: [Order] });    // eager (2.9)

// Tranzaksiya 2.10-bob: sequelize.transaction(async (t) => {...})
// Migration 2.11-bob: up/down + sequelize-cli
// Operatorlar 2.7-bob: { [Op.gt]: 18 }

4. Batafsil kod namunalari

Misol 1 — Ulanish (2.3)

js
// config/db.js
import { Sequelize } from "sequelize";
import { config } from "./index.js";              // (5.8)
import { logger } from "../utils/logger.js";

export const sequelize = new Sequelize(config.databaseUrl, {
  dialect: "postgres",
  logging: config.isProd ? false : (sql) => logger.debug(sql),   // dev'da SQL log (2.14)
  pool: { max: 10, min: 2, idle: 30000 },         // pool (6.5: 2.5)
});

export async function dbUlash() {
  try {
    await sequelize.authenticate();
    logger.info(" Sequelize ulandi");
  } catch (err) {
    logger.error(" Ulanmadi:", err.message);
    process.exit(1);                              // (5.8: fail fast)
  }
}

Misol 2 — Modellar (validatsiya, hook — 2.4, 2.6)

js
// models/user.js
import { DataTypes } from "sequelize";
import bcrypt from "bcrypt";
import { sequelize } from "../config/db.js";

export const User = sequelize.define("User", {
  id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
  ism: { type: DataTypes.STRING, allowNull: false, validate: { notEmpty: true } },
  email: {
    type: DataTypes.STRING, unique: true, allowNull: false,
    validate: { isEmail: { msg: "Email noto'g'ri" } },          // (2.6)
  },
  parol: { type: DataTypes.STRING, allowNull: false, validate: { len: [8, 100] } },
  rol: { type: DataTypes.ENUM("user", "admin"), defaultValue: "user" },
}, {
  timestamps: true,
  defaultScope: { attributes: { exclude: ["parol"] } },          // parolni qaytarma (14, 2.16)
  hooks: {
    beforeCreate: async (u) => { u.parol = await bcrypt.hash(u.parol, 12); },   // hash (5.15)
    beforeUpdate: async (u) => {
      if (u.changed("parol")) u.parol = await bcrypt.hash(u.parol, 12);
    },
  },
});

// Instance metod (parol solishtirish — 6.2: 2.17)
User.prototype.parolToOgri = function (p) { return bcrypt.compare(p, this.parol); };

Misol 3 — Bog'lanishlar (associations — 2.8)

js
// models/index.js — associate
import { User } from "./user.js";
import { Order } from "./order.js";
import { Product } from "./product.js";

// One-to-Many: User  Order (6.1: 2.5)
User.hasMany(Order, { foreignKey: "userId", as: "orders" });
Order.belongsTo(User, { foreignKey: "userId", as: "user" });

// Many-to-Many: Order  Product (junction: OrderItems — 2.8)
Order.belongsToMany(Product, { through: "OrderItems", foreignKey: "orderId" });
Product.belongsToMany(Order, { through: "OrderItems", foreignKey: "productId" });

export { User, Order, Product };

Misol 4 — CRUD service (2.5, 2.7)

js
import { Op } from "sequelize";
import { User } from "../models/index.js";

export const UserService = {
  yarat: (data) => User.create(data),             // hook parol hash (Misol 2)

  topId: (id) => User.findByPk(id),               // parolsiz (defaultScope — Misol 2)

  emailTop: (email) => User.scope(null).findOne({ where: { email } }),   // parol bilan (login — 5.15)

  royxat: ({ page = 1, limit = 20, qidiruv, rol }) => {
    const where = {};
    if (rol) where.rol = rol;
    if (qidiruv) where.ism = { [Op.iLike]: `%${qidiruv}%` };   // matn qidiruv (2.7)
    return User.findAndCountAll({                  // ma'lumot + umumiy son (sahifalash)
      where, limit, offset: (page - 1) * limit, order: [["createdAt", "DESC"]],
    });
  },

  yangila: async (id, data) => {
    const user = await User.findByPk(id);
    if (!user) return null;
    return user.update(data);                      // hook (Misol 2)
  },

  ochir: (id) => User.destroy({ where: { id } }),
};

Misol 5 — Eager loading (include — 2.9)

js
// Buyurtma + user + mahsulotlar (bitta so'rovda — JOIN — 2.9)
export const buyurtmaToliq = (id) => Order.findByPk(id, {
  include: [
    { model: User, as: "user", attributes: ["ism", "email"] },   // user (kerakli ustunlar)
    { model: Product, through: { attributes: ["miqdor", "narx"] } },   // mahsulotlar (junction)
  ],
});

// User + faqat tugallangan buyurtmalari (shartli include — 2.9)
export const userFaolBuyurtmalar = (userId) => User.findByPk(userId, {
  include: [{ model: Order, as: "orders", where: { holat: "tugallandi" }, required: false }],
});
// required: false  LEFT JOIN (buyurtmasi yo'q bo'lsa ham user chiqadi — 6.7: 2.3)

Misol 6 — Tranzaksiya (managed — 2.10)

js
import { sequelize } from "../config/db.js";

// Buyurtma yaratish — atomik (managed transaction — 2.10, 6.9)
export async function buyurtmaYarat(userId, items) {
  return sequelize.transaction(async (t) => {       // managed (avtomatik commit/rollback)
    // 1. Buyurtma yarat
    const order = await Order.create({ userId, holat: "yangi" }, { transaction: t });

    // 2. Har mahsulot — zaxira tekshir va kamaytir (atomik)
    for (const item of items) {
      const product = await Product.findByPk(item.productId, {
        transaction: t, lock: t.LOCK.UPDATE,        // FOR UPDATE (6.9: 2.13)
      });
      if (product.zaxira < item.miqdor) {
        throw new Error("Zaxira yetarli emas");      //  avtomatik ROLLBACK
      }
      product.zaxira -= item.miqdor;
      await product.save({ transaction: t });
      await OrderItem.create(
        { orderId: order.id, productId: item.productId, miqdor: item.miqdor, narx: product.narx },
        { transaction: t }
      );
    }
    return order;                                    // muvaffaqiyat  avtomatik COMMIT
  });
}

Misol 7 — Migration (2.11)

js
// migrations/20260101-create-users.js
export async function up(queryInterface, Sequelize) {
  await queryInterface.createTable("Users", {
    id: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true },
    ism: { type: Sequelize.STRING, allowNull: false },
    email: { type: Sequelize.STRING, allowNull: false, unique: true },
    parol: { type: Sequelize.STRING, allowNull: false },
    rol: { type: Sequelize.ENUM("user", "admin"), defaultValue: "user" },
    createdAt: { type: Sequelize.DATE, allowNull: false },
    updatedAt: { type: Sequelize.DATE, allowNull: false },
  });
  // Indeks qo'shish (6.10: 2.3)
  await queryInterface.addIndex("Users", ["email"]);
}

export async function down(queryInterface) {
  await queryInterface.dropTable("Users");          // qaytarish (2.11)
}
// Ishlatish: npx sequelize-cli db:migrate (qo'llash); db:migrate:undo (bekor)

Misol 8 — Migration: ustun qo'shish (2.11)

js
// Mavjud jadvalga ustun qo'shish (qo'lda ALTER emas — migration! — 2.11)
export async function up(queryInterface, Sequelize) {
  await queryInterface.addColumn("Users", "telefon", {
    type: Sequelize.STRING, allowNull: true,
  });
}
export async function down(queryInterface) {
  await queryInterface.removeColumn("Users", "telefon");   // qaytarish
}

Misol 9 — Express controller (5.6, 5.10)

js
import { UserService } from "../services/userService.js";

export const userlarOl = async (req, res, next) => {
  try {
    const { rows, count } = await UserService.royxat(req.query);   // findAndCountAll (Misol 4)
    res.json({ success: true, data: rows, jami: count });          // (5.7)
  } catch (err) { next(err); }
};

export const userYarat = async (req, res, next) => {
  try {
    const user = await UserService.yarat(req.body);
    res.status(201).json({ success: true, data: user });
  } catch (err) {
    if (err.name === "SequelizeUniqueConstraintError") {            // duplicate (2.16)
      return res.status(409).json({ error: "Email band" });        // (5.10)
    }
    if (err.name === "SequelizeValidationError") {                  // validatsiya
      return res.status(400).json({ error: err.errors.map(e => e.message) });
    }
    next(err);
  }
};

5. To'g'ri va noto'g'ri holatlar

1) N+1 (lazy loading tsiklda)

js
//  N+1 (har user — alohida so'rov — 2.14)
const users = await User.findAll();
for (const u of users) await u.getOrders();

//  eager (include — 1 so'rov)
const users = await User.findAll({ include: [Order] });

2) Qo'lda schema o'zgartirish (migrationsiz)

text
 DB'da qo'lda ALTER TABLE (muhitlar nomuvofiq — 2.11, 14)
 migration fayl (git, up/down)

3) Tranzaksiyada { transaction: t } unutish

js
//  tranzaksiyadan tashqarida (atomik emas — 2.10)
await sequelize.transaction(async (t) => {
  await User.update({...});   // t YO'Q!
});

//  har amalga t
await User.update({...}, { transaction: t });

4) Parolni qaytarish

js
//  parol JSON'da (14, 2.16)
const user = await User.findByPk(id);   // parol ham (scope yo'q bo'lsa)

//  defaultScope exclude (Misol 2)

5) Ortiqcha eager loading

js
//  kerakmas include (sekin, murakkab — 2.14)
await User.findAll({ include: [Order, Profile, Settings, Logs] });

//  faqat kerakli
await User.findAll({ include: [Order] });

6. Keng tarqalgan xatolar va yechimlari

Xato 1 — SequelizeConnectionError

Sababi: DB ishlamayapti, URL/dialect noto'g'ri 2.3-bob. Yechimi: DB ishga tushiring; DATABASE_URL/dialect tekshiring; driver o'rnatilgan (pg/mysql2).

Xato 2 — SequelizeUniqueConstraintError

Sababi: unique buzildi (email — 2.4). Yechimi: 409 qaytaring (Misol 9); oldindan tekshiring.

Xato 3 — SequelizeValidationError

Sababi: model validatsiyasi buzildi (isEmail, len — 2.6). Yechimi: ma'lumotni to'g'irlang; 400 (Misol 9); API validatsiya 5.9-bob.

Xato 4 — N+1 (sekin)

Sababi: lazy loading tsiklda 2.14-bob. Yechimi: include (eager); logging: true bilan SQL ko'ring.

Xato 5 — association ... is not associated

Sababi: include'dagi model associate qilinmagan 2.8-bob. Yechimi: hasMany/belongsTo ta'riflang (Misol 3); as mosligini tekshiring.

Xato 6 — Migration ishlamaydi

Sababi: config noto'g'ri, yoki migration sintaksisi 2.11-bob. Yechimi: .sequelizerc/config tekshiring; up/down to'g'ri; db:migrate:status.


7. Integratsiya — bu mavzu stack'ning qayerida uchraydi

  • SQL (6.4-6.10): ORM SQL ustida; SQL bilim shart.
  • MySQL/PostgreSQL (6.5, 6.6): Sequelize dialect.
  • Tranzaksiya/ACID 6.9-bob: sequelize.transaction.
  • Indeks/N+1 6.10-bob: eager loading, migration indeks.
  • Mongoose 6.2-bob: o'xshash ODM (NoSQL tomoni).
  • Prisma/TypeORM (6.12, 6.13): muqobil ORM'lar.
  • Auth 5.15-bob: User model, parol hash (hook).
  • Express 5.6-bob: model controller'da.
  • Migration/seed 6.16-bob: schema/ma'lumot boshqaruvi.
  • Xavfsizlik (14): injection (parametrli), maxfiy maydon.

8. Eng yaxshi amaliyotlar (best practices)

  • Migration har doim (qo'lda ALTER emas — git, up/down — 2.11, 14).
  • Tranzaksiya ko'p yozuvda (managed — { transaction: t } har amalga — 2.10).
  • Eager loading o'ylab (N+1 oldini oling, ortiqcha emas — 2.9, 2.14).
  • logging: true (dev) — generatsiya SQL'ni ko'ring (2.3, 2.14).
  • Validatsiya (model) + hook (parol hash — 2.6); API validatsiya ham 5.9-bob.
  • Maxfiy maydon scope'da yashiring (parol — defaultScope — 2.16).
  • Raw query parametrli (replacements — murakkab so'rov — 2.15, 14).
  • Xatolarni nom bo'yicha boshqaring (UniqueConstraint 409 — Misol 9, 5.10).
  • Indeks model/migration'da 6.10-bob; findAndCountAll (sahifalash — Misol 4).
  • SQL bilimini saqlang (ORM yashiradi, lekin kerak — 2.2).

9. Amaliy loyiha: "Sequelize bilan To'liq Backend"

Sequelize'ni professional darajada mustahkamlash.

Maqsad

Sequelize bilan to'liq, migration-asosli backend qurish: modellar, bog'lanishlar, tranzaksiya, eager loading va migration/seeding.

Talablar (requirements)

  1. Ulanish: Sequelize + pool; logging (dev); tekshiruv (Misol 1, 2.3).
  2. Modellar: User/Order/Product — validatsiya, hook (parol hash), defaultScope (Misol 2, 2.4, 2.6).
  3. Bog'lanishlar: one-to-many (User-Order), many-to-many (Order-Product — Misol 3, 2.8).
  4. CRUD service: Op operatorlar, findAndCountAll (sahifalash), qidiruv (Misol 4, 2.7).
  5. Eager loading: buyurtma+user+mahsulot; shartli include (Misol 5, 2.9).
  6. Tranzaksiya: buyurtma + zaxira (managed + lock — Misol 6, 2.10).
  7. Migration: jadval yaratish + ustun qo'shish (up/down — Misol 7, 8, 2.11).
  8. Seeding: boshlang'ich admin/kategoriya 2.12-bob.
  9. Express controller: xato boshqaruvi (UniqueConstraint409 — Misol 9).
  10. N+1 oldini olish: include bilan; logging bilan tekshiring 2.14-bob.

Maslahatlar (hint)

  • Bog'lanish: hasMany + belongsTo birga (2.8, 5-xato).
  • Eager: include (N+1 — 2.9, 2.14).
  • Tranzaksiya: managed + { transaction: t } har amalga (2.10, 3-xato).
  • Migration: sequelize-cli, up/down (2.11, 2-xato).
  • Parol: hook hash + defaultScope exclude (2.6, 2.16).
  • logging: true — SQL ko'ring 2.14-bob.

"Tayyor" mezonlari (acceptance criteria)

  • Sequelize ulanadi (pool, logging).
  • Modellar (validatsiya, hook, scope).
  • Bog'lanishlar (one-to-many, many-to-many).
  • CRUD (operatorlar, sahifalash, qidiruv).
  • Eager loading (include) ishlaydi.
  • Tranzaksiya (managed + lock).
  • Migration (yaratish + o'zgartirish).
  • Seeding (boshlang'ich ma'lumot).
  • Xato boshqaruvi (409/400).
  • N+1 yo'q (include bilan).

Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.


10. Xulosa va keyingi bobga ko'prik

Bu bobda birinchi ORM — Sequelize ni chuqur o'rgandik:

  • ORM (jadvalobyekt — 2.1); afzallik/kamchilik (yashirin SQL — 2.2); ORM SQL'ni almashtirmaydi (SQL bilim shart).
  • Model (define, DataTypes, validatsiya, hook — 2.4, 2.6); CRUD (findByPk/findAll/create — 2.5); Op operatorlar 2.7-bob.
  • Associations (hasMany/belongsTo/belongsToMany — 2.8); eager loading (include — JOIN — 2.9); tranzaksiya (managed — 2.10).
  • Migration (schema nazorat — up/down — 2.11) va seeding (boshlang'ich ma'lumot — 2.12); N+1 tuzog'i 2.14-bob; raw query 2.15-bob.

Keyingi bob — 6.12-bob: ORM — Prisma (schema, migrate, client, relations). Sequelize (klassik ORM) ni bildik; endi zamonaviy, type-safe ORM — Prisma ga o'tamiz. Prisma — boshqacha yondashuv: deklarativ schema fayli (schema.prisma), avtomatik generatsiya qilingan type-safe client, va ajoyib developer experience. TypeScript bilan eng yaxshi ORM hisoblanadi.


Foydalanilgan rasmiy/ishonchli manbalar

  • sequelize.org — Model definition, Associations, Transactions, Migrations, Validations
  • OneUptime — Sequelize ORM with Node.js 2026; sequelize.org/docs — eager loading, Op
  • sequelize-cli — migrations, seeders

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
6.11-bob: ORM — Sequelize (model, relations, migration) — Wisar