One-to-Many — embedding va referencing bilan

~20 daq · MongoDB · Schema Dizayn

Muammodan boshlaylik

Bir foydalanuvchining ko'p buyurtmasi bor. Bir post ning ko'p sharhi bor. Bir kategoriyaning ko'p mahsuloti bor.

Bu One-to-Many — bitta narsaga ko'p narsa tegishli.

MongoDB da buni ifodalashning uch usuli bor. Har birini qachon ishlatishni bilish muhim.


Uch usul

1. Embedded array         — kichiklar ichida
2. Reference (child side) — kichikda ota ID si
3. Reference (parent side)— otada kichiklar ID si

Usul 1 — Embedded array

Kichik documentlar ota document ichidagi massivda saqlanadi.

{
  "_id": "u1",
  "ism": "Jasur",
  "telefon_raqamlari": [
    { "tur": "uy",    "raqam": "+998901234567" },
    { "tur": "ish",   "raqam": "+998901234568" }
  ]
}
users
└── telefon_raqamlari: [ {...}, {...} ]

Qachon: Kichiklar soni kam (10 tagacha), faqat ota bilan birga kerak bo'lganda.

// Foydalanuvchi va telefon raqamlarini bir so'rovda olamiz
db.users.findOne({ _id: "u1" })

// Yangi raqam qo'shish
db.users.updateOne(
  { _id: "u1" },
  { $push: { telefon_raqamlari: { tur: "mobil", raqam: "+998901234569" } } }
)

Usul 2 — Reference (child side)

Kichik document da ota ning _id si saqlanadi. SQL da FOREIGN KEY.

// posts
{ "_id": "p1", "sarlavha": "MongoDB darsi" }

// comments
{ "_id": "c1", "post_id": "p1", "matn": "Yaxshi!" }
{ "_id": "c2", "post_id": "p1", "matn": "Rahmat"  }
{ "_id": "c3", "post_id": "p1", "matn": "Tushundim" }
posts            comments
─────            ────────
p1    ←──────── post_id: p1  (c1)
                post_id: p1  (c2)
                post_id: p1  (c3)

Qachon: Kichiklar ko'p bo'lsa, mustaqil ishlatiladigan bo'lsa.

// Post ning barcha sharhlari
db.comments.find({ post_id: "p1" })

// Sharh qo'shish — faqat shu collectionga
db.comments.insertOne({
  post_id: "p1",
  matn: "Yangi sharh",
  sana: new Date()
})

Usul 3 — Reference (parent side)

Ota document da kichiklar ning _id lari massiv sifatida saqlanadi.

// users
{
  "_id": "u1",
  "ism": "Jasur",
  "post_ids": ["p1", "p2", "p3"]
}

// posts
{ "_id": "p1", "sarlavha": "Dars 1" }
{ "_id": "p2", "sarlavha": "Dars 2" }
{ "_id": "p3", "sarlavha": "Dars 3" }
users
└── post_ids: [ p1, p2, p3 ]
                ↓   ↓   ↓
posts:         p1  p2  p3

Qachon: Kichiklar soni o'rtacha (yüzlargacha), ota tomonidan navigatsiya kerak bo'lganda.

// Foydalanuvchining post ID larini olish
let user = db.users.findOne({ _id: "u1" })

// Shu ID lar bo'yicha postlarni olish
db.posts.find({ _id: { $in: user.post_ids } })

Taqqoslash

                  Embedded     Child side   Parent side
                  ────────     ──────────   ───────────
Kichiklar soni    Kam (< 10)   Ko'p         O'rtacha
Alohida so'rov    Kerak emas   Kerak        Kerak
Kichikni o'chirish Qiyin       Oson         O'rtacha
Kichikni topish   Ota orqali   To'g'ridan   Ota orqali

Real misol — blog

// ✅ Muallif ma'lumoti — embedded (kichik, o'zgarmaydi)
{
  "_id": "p1",
  "sarlavha": "MongoDB darsi",
  "muallif": {
    "ism": "Jasur",
    "avatar": "/img/jasur.jpg"
  }
}
// ✅ Sharhlar — child side reference (ko'p bo'ladi)
// posts
{ "_id": "p1", "sarlavha": "MongoDB darsi" }

// comments
{ "_id": "c1", "post_id": "p1", "matn": "Yaxshi!" }
{ "_id": "c2", "post_id": "p1", "matn": "Tushundim" }
// ✅ Teglar — embedded array (kam, o'zgarmaydi)
{
  "_id": "p1",
  "sarlavha": "MongoDB darsi",
  "teglar": ["mongodb", "nosql", "database"]
}


Tez-tez uchraydigan xatolar

Array cheksiz o'sib ketishi

// ❌ — sharhlar soni ko'paysa document 16 MB dan oshadi
{
  "_id": "p1",
  "sarlavha": "Viral post",
  "sharhlar": [
    { ... }, { ... }, { ... }
    // ... 10 000 ta sharh
  ]
}
// ✅ — sharhlar alohida collection
// posts
{ "_id": "p1", "sarlavha": "Viral post" }

// comments
{ "post_id": "p1", "matn": "..." }   // 10 000 ta ham muammo emas

Parent side da ID massivi cheksiz o'sishi

// ❌ — bir foydalanuvchi millions likes qilsa
{
  "_id": "u1",
  "liked_post_ids": ["p1", "p2", ...]  // 100 000 ta ID
}
// ✅ — likes alohida collection
// likes
{ "foydalanuvchi_id": "u1", "post_id": "p1" }
{ "foydalanuvchi_id": "u1", "post_id": "p2" }

Xulosa

  • Embedded array — kichiklar kam, faqat ota bilan kerak
  • Child side reference — kichiklar ko'p, mustaqil ishlatiladigan
  • Parent side reference — kichiklar o'rtacha, ota orqali navigatsiya kerak
  • Array cheksiz o'smasligi kerak — document 16 MB limit bor
  • Ko'p sharh, ko'p buyurtma, ko'p like → child side yoki alohida collection

Keyingi dars: 15-dars — Many-to-Many — qanday loyihalash