Embedding vs Referencing — qachon qaysinisi

~25 daq · MongoDB · Schema Dizayn

Muammodan boshlaylik

Foydalanuvchining manzilini qayerda saqlash kerak?

Variant A — users document ichiga joylash:

{
  "_id": "u1",
  "ism": "Jasur",
  "manzil": {
    "shahar": "Toshkent",
    "ko'cha": "Navoiy 15"
  }
}

Variant B — alohida collection:

// users
{ "_id": "u1", "ism": "Jasur", "manzil_id": "m1" }

// manzillar
{ "_id": "m1", "shahar": "Toshkent", "ko'cha": "Navoiy 15" }

Qaysi biri to'g'ri? Javob: bog'liq. Bu darsda qachon qaysinisini tanlashni o'rganasiz.


Embedding nima?

Ma'lumotni boshqa document ichiga joylash.

{
  "_id": "u1",
  "ism": "Jasur",
  "manzil": {
    "shahar": "Toshkent",
    "ko'cha": "Navoiy 15"
  }
}

manzil — alohida collection emas, users document ichida.


Referencing nima?

Ma'lumotni alohida collection da saqlash, faqat ID sini ko'rsatish.

// users
{ "_id": "u1", "ism": "Jasur", "manzil_id": "m1" }

// manzillar
{ "_id": "m1", "shahar": "Toshkent", "ko'cha": "Navoiy 15" }

SQL da bu JOIN — users.manzil_id = manzillar._id.


Taqqoslash

                  EMBEDDING          REFERENCING
                  ─────────          ───────────
So'rov soni       1 ta               2 ta (yoki $lookup)
Tezlik            Tezroq             Sekinroq
Ma'lumot hajmi    Katta bo'lishi mumkin   Kichik
Yangilash         Har joyda yangilish     Bir joyda yangilash
Dublikat          Bor                Yo'q

Qachon Embedding?

1. Ma'lumot faqat shu document bilan ishlatilsa

Foydalanuvchining manzilini boshqa yerda ko'rsatmaysiz — faqat u bilan birga.

{
  "ism": "Jasur",
  "manzil": { "shahar": "Toshkent", "ko'cha": "Navoiy 15" }
}

2. Ma'lumot kichik va o'zgarmasa

Post ning muallif nomi — post yozilganda qanday bo'lsa, shunday qolsa yaxshi. Eski postlarda eski ism ko'rinishi normal.

{
  "sarlavha": "MongoDB darsi",
  "muallif": { "ism": "Jasur", "avatar": "/img/jasur.jpg" }
}

3. Birga o'qilsa

Buyurtma va uning mahsulotlari — har doim birga kerak.

{
  "_id": "b1",
  "sana": "2024-01-15",
  "mahsulotlar": [
    { "nom": "Olma", "miqdor": 2, "narx": 5000 },
    { "nom": "Nok",  "miqdor": 1, "narx": 8000 }
  ]
}

Bitta so'rov — hamma narsa keldi.


Qachon Referencing?

1. Ma'lumot ko'p joyda ishlatilsa

Muallif bir nechta post yozadi. Muallif nomi o'zgansa — barcha postlarda yangilash kerak.

// users
{ "_id": "u1", "ism": "Jasur" }

// posts
{ "sarlavha": "Dars 1", "muallif_id": "u1" }
{ "sarlavha": "Dars 2", "muallif_id": "u1" }
{ "sarlavha": "Dars 3", "muallif_id": "u1" }

Ism o'zgansa — faqat users da bir marta yangilanadi.

2. Ma'lumot katta yoki ko'p bo'lsa

Foydalanuvchining barcha buyurtmalari — yüzlab bo'lishi mumkin. Hammani users ichiga joylash noto'g'ri.

// users
{ "_id": "u1", "ism": "Jasur" }

// orders
{ "_id": "b1", "foydalanuvchi_id": "u1", "sana": "2024-01-01" }
{ "_id": "b2", "foydalanuvchi_id": "u1", "sana": "2024-02-01" }

3. Ma'lumot mustaqil ishlatiladigan bo'lsa

Mahsulot katalogdagi mahsulot — buyurtmasiz ham ko'rsatiladi, qidiriladi, filtrlanadi.


Misol — to'g'ri va noto'g'ri

Blog post

❌ Noto'g'ri — sharhlar ichida:

{
  "sarlavha": "Dars 1",
  "sharhlar": [
    { "matn": "Yaxshi!", "muallif": "Ali" },
    { "matn": "Rahmat", "muallif": "Vali" }
    // ... yüzlab sharh
  ]
}

Document 16 MB limitiga yetadi. Sharhlar alohida kerak bo'lganda ham butun post yuklanadi.

✅ To'g'ri — sharhlar alohida:

// posts
{ "_id": "p1", "sarlavha": "Dars 1" }

// comments
{ "_id": "c1", "post_id": "p1", "matn": "Yaxshi!", "muallif": "Ali" }
{ "_id": "c2", "post_id": "p1", "matn": "Rahmat",  "muallif": "Vali" }

Foydalanuvchi profili

✅ Manzil — ichida (faqat shu foydalanuvchi bilan):

{
  "_id": "u1",
  "ism": "Jasur",
  "manzil": { "shahar": "Toshkent" }
}

✅ Buyurtmalar — alohida (ko'p bo'ladi):

// users
{ "_id": "u1", "ism": "Jasur" }

// orders
{ "foydalanuvchi_id": "u1", "sana": "2024-01-01", "jami": 25000 }

Aralash yondashuv

Ko'p holatlarda ikkalasini birgalikda ishlatiladi.

{
  "_id": "b1",
  "foydalanuvchi_id": "u1",        // ← reference (foydalanuvchi alohida)
  "sana": "2024-01-15",
  "mahsulotlar": [                 // ← embedded (buyurtma bilan birga)
    { "nom": "Olma", "narx": 5000 },
    { "nom": "Nok",  "narx": 8000 }
  ]
}

Foydalanuvchi — reference (profil alohida kerak). Mahsulotlar — embedded (buyurtma bilan birga o'qiladi, narx o'sha vaqtdagi narx).


Qaror qabul qilish — oddiy qoida

Savol 1: Bu ma'lumot boshqa joyda ham ishlatiladi?
  YO'Q  → Embedding
  HA    → Referencing

Savol 2: Bu ma'lumot ko'p bo'lishi mumkinmi? (100+)
  YO'Q  → Embedding
  HA    → Referencing

Savol 3: Bu ma'lumot tez-tez o'zgariladimi?
  YO'Q  → Embedding
  HA    → Referencing

Uchala savolga YO'Q bo'lsa — Embedding
Birontasiga HA bo'lsa — Referencing ni ko'rib chiqing

Tez-tez uchraydigan xatolar

Hamma narsani ichiga joylash

// ❌ — foydalanuvchi ichida yüzlab buyurtma
{
  "ism": "Jasur",
  "buyurtmalar": [
    { ... }, { ... }, { ... }  // 500 ta bo'lib ketsa?
  ]
}

MongoDB document chegarasi — 16 MB. Array cheksiz o'smasligi kerak.

Hamma narsani alohida saqlash (SQL fikrlash)

// ❌ — manzil uchun alohida collection (keraksiz)
// users
{ "_id": "u1", "manzil_id": "m1" }

// manzillar
{ "_id": "m1", "shahar": "Toshkent" }
// Manzil faqat shu foydalanuvchi uchun — nima uchun alohida?

SQL da har narsa alohida jadval bo'ladi — MongoDB da bu kerak emas.


Xulosa

  • Embedding — birga o'qilsa, kichik bo'lsa, boshqa joyda kerak bo'lmasa
  • Referencing — ko'p joyda ishlatilsa, ko'p bo'lsa, tez-tez o'zgarsа
  • Ko'p holatlarda ikkalasi birgalikda — ba'zi maydonlar ichida, ba'zilari alohida
  • Document 16 MB chegarasi bor — cheksiz o'sadigan massivlarni ichiga joylaman

Keyingi dars: 14-dars — One-to-Many — embedding va referencing bilan