WisarWisar
Dasturlash kitobi/6-QISM — Database19 daqiqa

6.2-bob: MongoDB va Mongoose — CRUD, schema, model, query

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


1. Kirish va motivatsiya

6.1-bobda nazariy poydevorni qo'ydik (SQL vs NoSQL). Endi amaliyotga o'tamiz — eng mashhur NoSQL (document) bazasi MongoDB va Node.js uchun eng mashhur ODM Mongoose bilan ishlashni o'rganamiz. Bu — sizning stack'ingdagi asosiy DB; ko'p o'zbek loyihalari (startaplar, MVP, Telegram bot backend'lari — 5.14) MongoDB'da quriladi, chunki u tez boshlanadi va JavaScript bilan tabiiy ishlaydi.

MongoDB — document DB (6.1: hujjat). Ma'lumot JSON-ga o'xshash hujjatlarda saqlanadi — JavaScript obyektining aynan o'zi (2.8-JS). Bu — Node.js dasturchisi uchun ulkan qulaylik: DB'dan kelgan ma'lumot to'g'ridan JS obyekti, alohida "tarjima" kerak emas. Lekin xom MongoDB driver bilan ishlash — schema yo'q, validatsiya yo'q, hammasi qo'lda. Shuning uchun Mongoose ishlatiladi.

Mongoose — MongoDB uchun ODM (Object Data Modeling) — DB hujjatlarini JS obyektlariga "modellashtiruvchi" qatlam (mongoosejs.com). U MongoDB'ning moslashuvchanligiga schema, validatsiya, query qurish, hook qo'shadi — ya'ni NoSQL erkinligi + SQL intizomi balansi (6.1: 2.9). Bu bobda: ulanish, schema, model, CRUD (Create/Read/Update/Delete), va query operatorlarini chuqur o'rganamiz.

O'xshatish: xom MongoDB — qoidasiz daftar (xohlagan narsangni, xohlagan shaklda yozasiz — erkin, lekin chalkash). Mongoose — shaklli blank (forma) ustiga yozish: forma maydonlarni belgilaydi (schema), noto'g'ri to'ldirsangiz qabul qilmaydi (validatsiya), lekin baribir qog'oz (MongoDB) moslashuvchan. Erkinlik + tartib.

Nega muhim?

  • Stack asosi — MongoDB + Mongoose sizning stack'ingda; ko'p loyiha.
  • JS bilan tabiiy — document = JS obyekt; tez, qulay.
  • Schema + validatsiya — Mongoose NoSQL'ga intizom qo'shadi.
  • CRUD — har ilovaning asosiy amali; bu yerda mukammal o'rganamiz.

2. Nazariya — chuqur tushuntirish

2.1. MongoDB tuzilishi (database collection document)

text
  MongoDB server
  └── Database (ilova bazasi — "shop")
       └── Collection (jadval kabi — "users", "products")
            └── Document (hujjat — bitta yozuv, JSON kabi)
                 { _id: ObjectId("..."), ism: "Ali", yosh: 25 }

6.1 takrori: Collection = SQL jadval; Document = SQL qator; Field = ustun. Lekin document — moslashuvchan (har biri har xil shaklda bo'lishi mumkin — 6.1: 2.9).

2.2. _id va ObjectId (avtomatik identifikator)

Har document'da _id maydoni bor — noyob identifikator (SQL'dagi PK — 6.1: 2.4). MongoDB uni avtomatik yaratadi: ObjectId:

text
  _id: ObjectId("65a1b2c3d4e5f6a7b8c9d0e1")    12 baytli, noyob, vaqt ichida
  - global noyob (bir nechta server bo'lsa ham to'qnashmaydi)
  - yaratilgan vaqtni o'z ichiga oladi (ObjectId'dan sanani olish mumkin)

ObjectId — SQL'ning avtoincrement (1, 2, 3) o'rniga. Avtomatik, noyob, taqsimlangan tizimga mos (6.1: 2.14). Stringga aylantiriladi (_id.toString()).

2.3. Mongoose o'rnatish va ulanish

bash
npm install mongoose        # (5.2)
js
import mongoose from "mongoose";

await mongoose.connect(process.env.MONGO_URL);   // .env (5.8, 14)
// mongodb://localhost:27017/shop  (lokal)
// mongodb+srv://...  (Atlas — cloud)
console.log("MongoDB ulandi");

Ulanish manzili: lokal (mongodb://localhost:27017/dbnomi) yoki MongoDB Atlas (cloud — bepul tier bor). Parol .env'da (14). Ulanish — ilova boshida bir marta (6.17: connection pool Mongoose ichida).

2.4. Schema — document tuzilishi

Schema — collection document'larining tuzilishini belgilaydi (maydonlar, turlar, qoidalar — mongoosejs):

js
import mongoose from "mongoose";

const userSchema = new mongoose.Schema({
  ism: { type: String, required: true },        // matn, majburiy
  email: { type: String, required: true, unique: true },   // noyob
  yosh: { type: Number, min: 18 },              // son, minimal 18
  faol: { type: Boolean, default: true },       // boolean, standart qiymat
  rollar: [String],                              // string massivi
  yaratilgan: { type: Date, default: Date.now }, // sana
});

Schema turlari: String, Number, Boolean, Date, Array, ObjectId (bog'lanish — 2.13), Mixed, Buffer. Har maydonga qoidalar (required, unique, min/max, default, enum — 2.5). Bu — NoSQL'ga qo'shilgan intizom (6.1: 2.9).

2.5. Schema validatsiyasi (built-in)

Mongoose schema'da validatsiya (5.9 bilan bog'liq — DB darajasida):

js
const productSchema = new mongoose.Schema({
  nom: { type: String, required: [true, "Nom majburiy"], trim: true, minlength: 2 },
  narx: { type: Number, required: true, min: [0, "Narx manfiy bo'lmaydi"] },
  kategoriya: { type: String, enum: ["telefon", "kiyim", "kitob"] },   // faqat shu qiymatlar
  email: { type: String, match: /^\S+@\S+$/ },   // RegEx (2.13-JS)
});
// Noto'g'ri ma'lumot  save() xato beradi (ValidationError — 2.12)

DB darajasidagi validatsiya — qo'shimcha himoya qatlami (5.9: API validatsiya birinchi himoya; bu — ikkinchi). Ikkalasi birga — ishonchli.

2.6. Model — collection bilan ishlash vositasi

Model — schema'dan yaratiladigan, collection bilan CRUD qiluvchi obyekt (mongoosejs):

js
const User = mongoose.model("User", userSchema);   // "User"  "users" collection (avtomatik ko'plik)

// Endi User orqali CRUD:
await User.create({ ism: "Ali", email: "ali@a.uz" });   // qo'shish
await User.find();                                       // o'qish

Schema vs Model: schema — tuzilish (loyiha); model — shu tuzilma asosida ishlovchi (CRUD vositasi). Model nomi ("User") collection nomi (users — kichik, ko'plik) avtomatik.

2.7. Create (yaratish — C)

js
// create — yaratish va saqlash (bir qadamda)
const user = await User.create({ ism: "Ali", email: "ali@a.uz", yosh: 25 });

// yoki new + save (ikki qadam — hook/o'zgartirish uchun)
const user2 = new User({ ism: "Vali" });
await user2.save();

// ko'p hujjat
await User.insertMany([{ ism: "A" }, { ism: "B" }]);

2.8. Read (o'qish — R) va query operatorlar

js
await User.find();                              // hammasi (massiv)
await User.find({ yosh: 25 });                  // shartli (yosh = 25)
await User.findOne({ email: "ali@a.uz" });      // bittasi (yoki null)
await User.findById("65a1...");                 // _id bo'yicha

// Query operatorlari (MongoDB — mongoosejs):
await User.find({ yosh: { $gt: 18 } });         // > 18 (gt: greater than)
await User.find({ yosh: { $gte: 18, $lte: 60 } });  // 18-60 oralig'i
await User.find({ rol: { $in: ["admin", "moderator"] } });   // ro'yxatda
await User.find({ ism: { $regex: /ali/i } });   // matn qidiruv (RegEx)
await User.find({ $or: [{ yosh: 18 }, { vip: true }] });   // yoki

Query operatorlari: $gt/$gte/$lt/$lte (taqqoslash), $in/$nin (ro'yxat), $or/$and (mantiq), $regex (matn), $exists (maydon bormi). MongoDB shell sintaksisi bilan bir xil (manba). Bular — so'rovning kuchi.

2.9. Query zanjiri (sort, limit, select, skip)

js
await User.find({ faol: true })
  .sort({ yosh: -1 })            // yosh bo'yicha kamayish (-1; 1 — o'sish)
  .limit(10)                      // 10 ta (sahifalash — 5.7)
  .skip(20)                       // 20 tasini o'tkazib (page 3)
  .select("ism email -_id");      // faqat ism, email (_id'siz)

Query zanjiri — so'rovni nozik sozlash: sort (tartib), limit/skip (sahifalash — 5.7), select (qaysi maydonlar — kerakmas ma'lumotni olmaslik). Bu — performance uchun muhim.

2.10. Update (yangilash — U)

js
// findByIdAndUpdate — top va yangila (yangisini qaytaradi)
await User.findByIdAndUpdate(id, { yosh: 26 }, { new: true, runValidators: true });
// new: true  YANGI hujjatni qaytaradi (default: eski); runValidators  validatsiya ishlasin

// updateOne / updateMany — qaytarmaydi (faqat yangilaydi)
await User.updateOne({ _id: id }, { $set: { faol: false } });
await User.updateMany({ yosh: { $lt: 18 } }, { $set: { voyaga: false } });

// Update operatorlari
{ $set: { ism: "Yangi" } }       // qiymat o'rnatish
{ $inc: { ko'rishlar: 1 } }      // oshirish (atomik — 5.21)
{ $push: { teglar: "yangi" } }   // massivga qo'shish
{ $pull: { teglar: "eski" } }    // massivdan o'chirish

runValidators: true — update'da validatsiya default'da ishlamaydi (faqat create/save'da). Yangilashda ham tekshirish kerak bo'lsa, qo'shish shart 2.5-bob.

2.11. Delete (o'chirish — D)

js
await User.findByIdAndDelete(id);               // top va o'chir
await User.deleteOne({ email: "ali@a.uz" });    // bittasi
await User.deleteMany({ faol: false });         // ko'pi

// Soft delete (tavsiya — ma'lumotni butunlay yo'qotmaslik):
await User.findByIdAndUpdate(id, { ochirilgan: true });   // belgilab qo'yish
// keyin find({ ochirilgan: { $ne: true } }) — o'chirilmaganlar

Soft delete: ko'p real ilovada ma'lumot butunlay o'chirilmaydiochirilgan: true deb belgilanadi (tiklash mumkin, audit, bog'liq ma'lumot buzilmaydi). Hard delete (butunlay) — ehtiyot bilan.

2.12. Xatolar va validatsiya (5.10 bilan)

js
try {
  await User.create({ email: "ali@a.uz" });   // ism yo'q (required!)
} catch (err) {
  if (err.name === "ValidationError") { /* 400 — 5.10 */ }   // schema buzildi
  if (err.code === 11000) { /* 409 — duplicate (unique) — 5.10 */ }  // email band
}

Bu xatolar 5.10 (error handler) da moslangan edi: ValidationError 400, 11000 (duplicate key) 409. Mongoose xatolari — global handler'da boshqariladi.

2.13. Relations — reference va populate (JOIN o'rni)

MongoDB'da JOIN yo'q (6.1: 2.16), lekin reference (ishora) + populate bilan bog'lanish (mongoosejs):

js
// Order schema — user'ga ishora (reference — 6.1: 2.5)
const orderSchema = new mongoose.Schema({
  user: { type: mongoose.Schema.Types.ObjectId, ref: "User" },   // User'ga ishora
  summa: Number,
});

// populate — ishorani TO'LDIRISH (user ma'lumotini olib keladi — JOIN kabi)
const order = await Order.findById(id).populate("user");
// order.user — endi to'liq User obyekti (faqat _id emas)
console.log(order.user.ism);   // "Ali"

populate — MongoDB'ning "JOIN"i (6.1: 2.16): reference'ni (faqat _id) to'liq hujjatga almashtiradi. Lekin bu — qo'shimcha so'rov (SQL JOIN bitta so'rovda). Shuning uchun ba'zan embed (birga saqlash — 6.3) afzal. 6.3-bobda chuqur (embed vs reference).

2.14. lean() — tezlik uchun (performance)

Mongoose find natijasi — to'liq Mongoose document (metodlar, hook bilan — og'ir). Faqat o'qish kerak bo'lsa, lean() — oddiy JS obyekt (tezroq):

js
await User.find().lean();   // oddiy JS obyekt (Mongoose document emas — tez)

lean() o'qish (read-only) uchun: API javobida ma'lumotni qaytarsangiz (o'zgartirmasdan), lean() — sezilarli tezroq (Mongoose "og'ir" obyekt yasamaydi). Lekin save(), virtual, hook ishlamaydi (faqat oddiy ma'lumot).

2.15. Indekslar (qidiruv tezligi — kirish)

Indeks — qidiruvni tezlashtiradi (kitobning mundarijasi kabi):

js
const userSchema = new mongoose.Schema({
  email: { type: String, unique: true, index: true },   // email bo'yicha indeks
});
userSchema.index({ ism: 1, yosh: -1 });   // birikma indeks (ism o'sish, yosh kamayish)

Indeks nima: indekssiz qidiruv — butun collection'ni ko'rib chiqish (sekin — million hujjat). Indeks bilan — to'g'ridan topish (tez). Tez-tez qidiriladigan maydonga indeks (email, user_id). Lekin har indeks — yozishni sekinlatadi va joy oladi (balans). 6.3-bobda chuqur.

2.16. Schema hook'lar (middleware)

Schema'ga hook (middleware) — amaldan oldin/keyin avtomatik kod (5.15: parol hash misoli):

js
userSchema.pre("save", async function (next) {     // saqlashdan OLDIN
  if (this.isModified("parol")) {
    this.parol = await bcrypt.hash(this.parol, 12);  // parolni hash (5.15)
  }
  next();
});
userSchema.post("save", function (doc) {           // saqlashdan KEYIN
  console.log(`${doc.ism} saqlandi`);
});

Hook'larpre/post (save, find, delete...). Foydali: parol hash 5.15-bob, slug yaratish, log, tozalash. Schema mantig'ini bir joyda saqlaydi (DRY).

2.17. Virtual va metodlar (qo'shimcha)

js
// Virtual — saqlanmaydigan, hisoblanadigan maydon
userSchema.virtual("toliqIsm").get(function () {
  return `${this.ism} ${this.familiya}`;   // DB'da yo'q, lekin obyektda bor
});

// Instance metod — har hujjatda
userSchema.methods.parolToOgri = function (p) {
  return bcrypt.compare(p, this.parol);    // (5.15)
};

// Static metod — model darajasida
userSchema.statics.faollar = function () {
  return this.find({ faol: true });
};

2.18. Xavfsizlik (NoSQL injection — 14)

text
   NoSQL injection: foydalanuvchi kiritgan obyektni to'g'ridan query'ga solmang
     User.find({ email: req.body.email })  — agar email = { $gt: "" } bo'lsa, hammasi!
     validatsiya 5.9-bob + tur tekshiruv; express-mongo-sanitize 5.20-bob
   DB URL .env'da (14, 5.8)
   select: false maxfiy maydon (parol — 5.15)
   Faqat kerakli maydonlarni qaytaring (select — 2.9; maxfiyni yashiring)

3. Sintaksis — tez ma'lumotnoma

js
import mongoose from "mongoose";
await mongoose.connect(process.env.MONGO_URL);              // ulanish (2.3)

const schema = new mongoose.Schema({ ism: { type: String, required: true } });   // (2.4)
const User = mongoose.model("User", schema);               // model (2.6)

// CRUD (2.7-2.11)
await User.create({ ism: "Ali" });                          // C
await User.find({ yosh: { $gt: 18 } }).sort({ ism: 1 }).limit(10).lean();   // R (2.8, 2.9, 2.14)
await User.findByIdAndUpdate(id, { yosh: 26 }, { new: true, runValidators: true });   // U
await User.findByIdAndDelete(id);                           // D

// Relations 2.13-bob: ref + .populate("user")
// Hook 2.16-bob: schema.pre("save", fn)

4. Batafsil kod namunalari

Misol 1 — Ulanish (xato boshqaruvi bilan — 2.3)

js
import mongoose from "mongoose";
import { config } from "./config/index.js";        // (5.8)
import { logger } from "./utils/logger.js";          // (5.12)

export async function dbUlash() {
  try {
    await mongoose.connect(config.mongoUrl);          // (2.3)
    logger.info(" MongoDB ulandi");
  } catch (err) {
    logger.error(" MongoDB ulanmadi:", err.message);   // (5.12)
    process.exit(1);                                  // ulanmasa to'xta (5.8: fail fast)
  }
}
mongoose.connection.on("disconnected", () => logger.warn("MongoDB uzildi"));   // (5.12)

Misol 2 — To'liq schema (validatsiya, hook — 2.4, 2.5, 2.16)

js
import mongoose from "mongoose";
import bcrypt from "bcrypt";                          // (5.15)

const userSchema = new mongoose.Schema({
  ism: { type: String, required: [true, "Ism majburiy"], trim: true, minlength: 2 },
  email: {
    type: String, required: true, unique: true, lowercase: true,
    match: [/^\S+@\S+\.\S+$/, "Email noto'g'ri"],     // RegEx (2.5)
  },
  parol: { type: String, required: true, minlength: 8, select: false },   // maxfiy (2.18, 5.15)
  rol: { type: String, enum: ["user", "admin"], default: "user" },        // (2.5, 5.17)
  faol: { type: Boolean, default: true },
}, { timestamps: true });                              // createdAt, updatedAt avtomatik

// Hook — parolni hash (2.16, 5.15)
userSchema.pre("save", async function (next) {
  if (!this.isModified("parol")) return next();
  this.parol = await bcrypt.hash(this.parol, 12);
  next();
});

// Metod — parol solishtirish (2.17, 5.15)
userSchema.methods.parolToOgri = function (p) {
  return bcrypt.compare(p, this.parol);
};

export const User = mongoose.model("User", userSchema);

Misol 3 — Create (xato boshqaruvi — 2.7, 2.12)

js
import { User } from "../models/User.js";

export const userYarat = async (req, res, next) => {
  try {
    const user = await User.create(req.body);          // validatsiya avtomatik (2.5)
    const { parol, ...natija } = user.toObject();       // parolni olib tashla (2.18)
    res.status(201).json({ success: true, data: natija });   // (5.7)
  } catch (err) {
    if (err.code === 11000) {                           // duplicate (email band — 2.12)
      return res.status(409).json({ error: "Email allaqachon mavjud" });
    }
    next(err);                                          // ValidationError  400 (5.10)
  }
};

Misol 4 — Read: filtr, sahifalash, qidiruv (2.8, 2.9)

js
export const userlarOl = async (req, res, next) => {
  try {
    const { page = 1, limit = 20, qidiruv, rol } = req.query;   // (5.7, validatsiya — 5.9)

    // Dinamik filtr qurish (2.8)
    const filtr = {};
    if (rol) filtr.rol = rol;
    if (qidiruv) filtr.ism = { $regex: qidiruv, $options: "i" };   // matn qidiruv (2.8)

    const userlar = await User.find(filtr)
      .sort({ createdAt: -1 })                          // yangi birinchi (2.9)
      .skip((page - 1) * limit)                          // sahifalash (2.9)
      .limit(Number(limit))
      .select("-parol")                                  // parolsiz (2.18)
      .lean();                                           // tez (2.14)

    const jami = await User.countDocuments(filtr);       // umumiy son (sahifalash uchun)
    res.json({ success: true, data: userlar, jami, page: Number(page) });   // (5.7)
  } catch (err) { next(err); }
};

Misol 5 — Update (runValidators — 2.10)

js
export const userYangila = async (req, res, next) => {
  try {
    const user = await User.findByIdAndUpdate(
      req.params.id,
      { $set: req.body },                                // faqat berilgan maydonlar
      { new: true, runValidators: true }                // yangisini qaytar + validatsiya (2.10)
    ).select("-parol");
    if (!user) return res.status(404).json({ error: "Topilmadi" });   // (5.7)
    res.json({ success: true, data: user });
  } catch (err) { next(err); }
};

// Atomik operatorlar (2.10)
await Product.findByIdAndUpdate(id, { $inc: { korishlar: 1 } });        // ko'rishlar +1
await User.findByIdAndUpdate(id, { $push: { teglar: "vip" } });        // teg qo'shish

Misol 6 — Delete (soft delete — 2.11)

js
// Soft delete (belgilash — 2.11)
export const userOchir = async (req, res, next) => {
  try {
    const user = await User.findByIdAndUpdate(
      req.params.id,
      { ochirilgan: true, ochirilganVaqt: new Date() },   // belgilab qo'yish
      { new: true }
    );
    if (!user) return res.status(404).json({ error: "Topilmadi" });
    res.json({ success: true, message: "O'chirildi" });
  } catch (err) { next(err); }
};
// O'qishda o'chirilmaganlar: User.find({ ochirilgan: { $ne: true } }) (2.11)

Misol 7 — Relations: reference + populate (2.13)

js
// Order modeli — user va mahsulotlarga ishora (2.13)
const orderSchema = new mongoose.Schema({
  user: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: true },
  mahsulotlar: [{ type: mongoose.Schema.Types.ObjectId, ref: "Product" }],
  summa: Number,
  holat: { type: String, enum: ["yangi", "tasdiqlandi", "yetkazildi"], default: "yangi" },
}, { timestamps: true });
export const Order = mongoose.model("Order", orderSchema);

// populate — ishoralarni to'ldirish (2.13)
const order = await Order.findById(id)
  .populate("user", "ism email")                       // user'ning faqat ism/email
  .populate("mahsulotlar", "nom narx")                 // mahsulotlar tafsiloti
  .lean();
// order.user.ism, order.mahsulotlar[0].nom — to'liq ma'lumot (JOIN kabi)

Misol 8 — Repository naqsh (toza arxitektura — 9)

js
// Service/repository qatlam — DB mantig'ini ajratish (9: Clean Architecture)
export class UserService {
  static async yarat(data) { return User.create(data); }
  static async topId(id) { return User.findById(id).select("-parol").lean(); }
  static async emailTop(email) { return User.findOne({ email }).select("+parol"); }   // parol bilan (login — 5.15)
  static async royxat({ page, limit, filtr }) {
    return User.find(filtr).skip((page - 1) * limit).limit(limit).lean();
  }
  static async yangila(id, data) {
    return User.findByIdAndUpdate(id, data, { new: true, runValidators: true });
  }
}
// Controller 5.6-bob faqat HTTP; DB mantig'i — service'da (toza — 9)

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

1) Update'da runValidators'siz

js
//  validatsiya ishlamaydi (noto'g'ri ma'lumot kiradi — 2.10)
await User.findByIdAndUpdate(id, { yosh: -5 });

//  runValidators
await User.findByIdAndUpdate(id, { yosh: -5 }, { runValidators: true });   // xato beradi

2) findByIdAndUpdatenew: true'siz (eski hujjat qaytadi)

js
//  default: YANGILANISHDAN OLDINGI hujjat qaytadi (2.10)
const u = await User.findByIdAndUpdate(id, { yosh: 26 });
console.log(u.yosh);   // 25 — eski qiymat! (yangilandi, lekin qaytgani eski)

//  new: true  yangilangan hujjat qaytadi
const u2 = await User.findByIdAndUpdate(id, { yosh: 26 }, { new: true });
console.log(u2.yosh);   // 26 — to'g'ri

3) Parolni javobda qaytarish

js
//  parol JSON'da (14, 2.18)
const user = await User.findById(id);   // parol ham keladi

//  select: false (schema) + select("-parol")
const user = await User.findById(id).select("-parol");

4) NoSQL injection

js
//  foydalanuvchi obyektini to'g'ridan (14, 2.18)
await User.findOne({ email: req.body.email });   // email = { $gt: "" }  hammasi!

//  validatsiya + tur tekshiring (5.9, mongo-sanitize — 5.20)

5) Katta natijani lean()'siz qaytarish

js
//  to'liq Mongoose document (og'ir — 2.14)
const users = await User.find();

//  o'qish uchun lean
const users = await User.find().lean();

6) populate'ni ko'p ishlatish (N+1)

text
 har element uchun alohida populate (ko'p so'rov — sekin)
 kerakli joyda; ko'p o'qiladigan ma'lumot — embed (6.3)

6. Keng tarqalgan xatolar va yechimlari

Xato 1 — MongooseServerSelectionError (ulanmaydi)

Sababi: MongoDB ishlamayapti, URL noto'g'ri, yoki Atlas IP ruxsati 2.3-bob. Yechimi: MongoDB ishga tushiring; MONGO_URL tekshiring; Atlas'da IP whitelist.

Xato 2 — ValidationError

Sababi: schema qoidasi buzildi (required, enum — 2.5). Yechimi: ma'lumotni to'g'irlang; API validatsiya 5.9-bob; 400 qaytaring 5.10-bob.

Xato 3 — E11000 duplicate key

Sababi: unique maydon takrorlandi (email — 2.5). Yechimi: 409 qaytaring 5.10-bob; oldindan tekshiring.

Xato 4 — Update validatsiya ishlamaydi

Sababi: runValidators yo'q 2.10-bob. Yechimi: { runValidators: true }.

Xato 5 — populate null qaytaradi

Sababi: ref nomi model nomiga mos emas, yoki ishora qilingan hujjat yo'q 2.13-bob. Yechimi: ref: "User" model nomiga aniq mos; ishora to'g'ri.

Xato 6 — Cast to ObjectId failed

Sababi: noto'g'ri formatdagi id (findById("abc") — 2.2). Yechimi: id formatini validatsiya (5.9: mongoose.isValidObjectId).


7. Integratsiya — bu mavzu stack'ning qayerida uchraydi

  • DB asoslari 6.1-bob: MongoDB — document NoSQL.
  • Express 5.6-bob: model'lar controller'da; CRUD endpoint.
  • Validatsiya 5.9-bob: API validatsiya + schema validatsiya (ikki qatlam).
  • Error handling 5.10-bob: ValidationError/11000 400/409.
  • Auth 5.15-bob: User model, parol hash (hook).
  • Env 5.8-bob: MONGO_URL.
  • Relations/aggregation 6.3-bob: keyingi bob (chuqur).
  • Xavfsizlik (14): NoSQL injection, maxfiy maydon.
  • NestJS 8.13-bob: @nestjs/mongoose — shu g'oya.
  • Clean architecture (9): repository/service qatlam.

8. Eng yaxshi amaliyotlar (best practices)

  • Schema + validatsiya (NoSQL'ga intizom — 2.4, 2.5); timestamps: true.
  • Update'da runValidators: true 2.10-bob.
  • Maxfiy maydon select: false + select("-parol") (parol — 2.18, 14).
  • O'qishda lean() (tezlik — 2.14).
  • select bilan kerakli maydonlar (kerakmasini olmang — 2.9).
  • Hook'da umumiy mantiq (parol hash, slug — 2.16, DRY).
  • Indeks tez-qidiriladigan maydonga (email, ref — 2.15).
  • NoSQL injection himoyasi (validatsiya, sanitize — 2.18, 14).
  • Soft delete (muhim ma'lumot — 2.11).
  • Service/repository qatlam (DB mantig'ini ajrating — toza — Misol 8, 9).
  • populate o'rniga embed (ko'p-o'qiladigan ma'lumot — 6.3).

9. Amaliy loyiha: "MongoDB + Mongoose CRUD API"

MongoDB va Mongoose'ni professional darajada mustahkamlash.

Maqsad

Mongoose bilan to'liq CRUD API qurish: schema (validatsiya, hook), model, CRUD endpoint'lar, filtr/sahifalash/qidiruv va relations (populate).

Talablar (requirements)

  1. Ulanish: Mongoose + .env URL; xato boshqaruvi (Misol 1, 2.3).
  2. Schema'lar: User va Product (yoki o'z mavzun) — validatsiya, enum, default, timestamps, select:false (Misol 2, 2.4, 2.5).
  3. Hook: parol hash (pre-save — 2.16, 5.15).
  4. CRUD endpoint'lar: create/read/update/delete — error handling bilan (Misol 3-6, 5.10).
  5. Read: filtr (rol/kategoriya), qidiruv (regex), sahifalash (skip/limit), select, lean (Misol 4, 2.8, 2.9).
  6. Update: runValidators; atomik operatorlar ($inc/$push — Misol 5, 2.10).
  7. Soft delete: belgilab o'chirish (Misol 6, 2.11).
  8. Relations: Order User/Product (reference + populate — Misol 7, 2.13).
  9. Service qatlam: DB mantig'ini ajratish (Misol 8, 9).
  10. Xavfsizlik: parolni qaytarmaslik; NoSQL injection himoyasi (2.18, 14).

Maslahatlar (hint)

  • timestamps: true (createdAt/updatedAt avtomatik — 2.4).
  • Update: { new: true, runValidators: true } (2.10, 4-xato).
  • Parol: select: false + hook hash (2.16, 2.18).
  • Qidiruv: { $regex: q, $options: "i" } 2.8-bob.
  • Sahifalash: .skip((page-1)*limit).limit(limit) 2.9-bob.
  • populate: ref model nomiga mos (2.13, 5-xato).
  • O'qishda .lean() 2.14-bob.

"Tayyor" mezonlari (acceptance criteria)

  • MongoDB ulanadi (xato boshqaruvi).
  • Schema validatsiya ishlaydi (noto'g'ri ma'lumot rad).
  • CRUD endpoint'lar ishlaydi (error handling bilan).
  • Filtr/qidiruv/sahifalash ishlaydi.
  • Update validatsiya bilan; atomik operatorlar.
  • Soft delete.
  • Relations (populate) ishlaydi.
  • Parol hech qachon qaytmaydi.
  • Service qatlam (toza arxitektura).

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


10. Xulosa va keyingi bobga ko'prik

Bu bobda MongoDB va Mongoose bilan amaliy ishlashni o'rgandik:

  • MongoDB tuzilishi (database/collection/document — 2.1); _id/ObjectId 2.2-bob; Mongoose ODM (schema/validatsiya/model — 2.3-2.6).
  • CRUD: create 2.7-bob, read + query operatorlar ($gt/$in/$regex — 2.8) + query zanjiri (sort/limit/select — 2.9), update (runValidators, $inc/$push — 2.10), delete (soft delete — 2.11).
  • Relations (reference + populate — JOIN o'rni — 2.13); lean() (tezlik — 2.14); indeks 2.15-bob; hook/virtual/metod (2.16, 2.17).
  • Xavfsizlik (NoSQL injection, maxfiy maydon — 2.18); xatolar (ValidationError/11000 — 2.12, 5.10).

Keyingi bob — 6.3-bob: MongoDB chuqur — aggregation pipeline, indekslar, relations. Asosiy CRUD'ni bildik; endi MongoDB'ning kuchli imkoniyatlarini — aggregation pipeline (murakkab ma'lumot tahlili, guruhlash, hisoblash), indekslar (qidiruv optimizatsiyasi, chuqur), va relations (embed vs reference — qachon qaysi biri) — chuqur o'rganamiz.


Foydalanilgan rasmiy/ishonchli manbalar

  • mongoosejs.com — Schema, Model, Queries, Validation, Populate, Middleware (hooks)
  • mongodb.com/docs — Mongoose integration; MDN — Express + Mongoose tutorial
  • mongoosejs.com/docs/queries — query operatorlar, lean

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
6.2-bob: MongoDB va Mongoose — CRUD, schema, model, query — Wisar