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)
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:
_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
npm install mongoose # (5.2)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):
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):
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):
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'qishSchema 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)
// 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
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 }] }); // yokiQuery 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)
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)
// 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)
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'chirilmaganlarSoft delete: ko'p real ilovada ma'lumot butunlay o'chirilmaydi —
ochirilgan: truedeb belgilanadi (tiklash mumkin, audit, bog'liq ma'lumot buzilmaydi). Hard delete (butunlay) — ehtiyot bilan.
2.12. Xatolar va validatsiya (5.10 bilan)
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:
ValidationError400,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):
// 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):
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). Lekinsave(), virtual, hook ishlamaydi (faqat oddiy ma'lumot).
2.15. Indekslar (qidiruv tezligi — kirish)
Indeks — qidiruvni tezlashtiradi (kitobning mundarijasi kabi):
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):
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'lar —
pre/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)
// 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)
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
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)
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)
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)
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)
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)
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'shishMisol 6 — Delete (soft delete — 2.11)
// 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)
// 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)
// 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
// 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 beradi2) findByIdAndUpdate — new: true'siz (eski hujjat qaytadi)
// 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'ri3) Parolni javobda qaytarish
// 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
// 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
// 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)
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: true2.10-bob. - Maxfiy maydon
select: false+select("-parol")(parol — 2.18, 14). - O'qishda
lean()(tezlik — 2.14). selectbilan 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)
- Ulanish: Mongoose + .env URL; xato boshqaruvi (Misol 1, 2.3).
- Schema'lar: User va Product (yoki o'z mavzun) — validatsiya, enum, default, timestamps, select:false (Misol 2, 2.4, 2.5).
- Hook: parol hash (pre-save — 2.16, 5.15).
- CRUD endpoint'lar: create/read/update/delete — error handling bilan (Misol 3-6, 5.10).
- Read: filtr (rol/kategoriya), qidiruv (regex), sahifalash (skip/limit), select, lean (Misol 4, 2.8, 2.9).
- Update: runValidators; atomik operatorlar ($inc/$push — Misol 5, 2.10).
- Soft delete: belgilab o'chirish (Misol 6, 2.11).
- Relations: Order User/Product (reference + populate — Misol 7, 2.13).
- Service qatlam: DB mantig'ini ajratish (Misol 8, 9).
- 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:
refmodel 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!