Schema Patterns — Bucket, Outlier, Computed, Subset

~25 daq · MongoDB · Schema Dizayn

Muammodan boshlaylik

Ba'zi muammolar oddiy embedding yoki referencing bilan hal bo'lmaydi. Ilovangiz o'sib boradi — ma'lumot ko'payadi, so'rovlar sekinlashadi.

Bu darsda real loyihalarda ishlatiladigan 4 ta schema pattern — har birining muammo va yechimi.


Bucket Pattern

Muammo

Har soniyada sensor harorat o'lchaydi. Bir yilda 31 million yozuv. Har o'lchov uchun alohida document — collection katta, so'rovlar sekin.

// ❌ Har o'lchov — alohida document (31 million ta)
{ "sensor": "s1", "vaqt": "2024-01-01T00:00:01", "harorat": 22.5 }
{ "sensor": "s1", "vaqt": "2024-01-01T00:00:02", "harorat": 22.6 }
{ "sensor": "s1", "vaqt": "2024-01-01T00:00:03", "harorat": 22.4 }

Yechim

Bir soatlik o'lchashlarni bitta document ga yig'amiz.

// ✅ Bir soatlik o'lchashlar — bitta document
{
  "sensor":      "s1",
  "soat":        "2024-01-01T00:00:00",
  "o_lchashlar": [
    { "daqiqa": 0, "harorat": 22.5 },
    { "daqiqa": 1, "harorat": 22.6 },
    { "daqiqa": 2, "harorat": 22.4 }
  ],
  "min":      22.1,
  "max":      23.0,
  "o_rtacha": 22.5
}
Oldin: 31 000 000 ta document
Keyin:    525 600 ta document
          ↑ 60 marta kamroq
// Yangi o'lchov qo'shish
db.sensorlar.updateOne(
  { sensor: "s1", soat: "2024-01-01T00:00:00" },
  { $push: { o_lchashlar: { daqiqa: 3, harorat: 22.7 } } },
  { upsert: true }
)

Qachon ishlatiladi: Vaqt bo'yicha keluvchi ma'lumot — sensor, analytics, server loglari.


Outlier Pattern

Muammo

Ko'pchilik foydalanuvchi 50-100 ta post yozadi. Lekin mashhur blogger 500 000 ta post yozdi. Uning document i 16 MB dan oshib ketdi.

// ❌ — 500 000 ta post_id bitta documentda
{
  "_id": "u_yasmin",
  "ism": "Yasmin",
  "post_ids": ["p1", "p2", "p3", ...]   // 500 000 ta → 16 MB!
}

Yechim

Asosiy document da faqat so'nggi postlar. Qolganlar — alohida overflow document da.

// Asosiy document — so'nggi postlar
{
  "_id": "u_yasmin",
  "ism": "Yasmin",
  "post_ids": ["p499998", "p499999", "p500000"],
  "overflow": true    // ← yana ko'proq bor
}

// Overflow document — eski postlar
{
  "foydalanuvchi_id": "u_yasmin",
  "post_ids": ["p1", "p2", ..., "p499997"]
}
Ko'pchilik foydalanuvchi:  overflow yo'q, oddiy document
Mashhur blogger:           overflow: true, alohida document

Qachon ishlatiladi: Ko'pchilik uchun ma'lumot o'rtacha, lekin nodir holatlarda juda ko'p bo'lganda.


Computed Pattern

Muammo

Bosh sahifada: "Bugungi eng ko'p sotilgan 10 ta mahsulot". Har bir sahifa ochilganda millionlab buyurtma hisoblanadi — sekin.

Har foydalanuvchi bosh sahifani ochsa → 1 000 000 buyurtma hisoblanadi
1000 foydalanuvchi bir vaqtda → 1 000 000 000 ta hisob-kitob

Yechim

Natijani oldindan hisoblab, alohida document da saqlash. Sahifa ochilganda — faqat o'sha documentni o'qish.

// top_mahsulotlar — oldindan hisoblangan
{
  "sana": "2024-01-15",
  "top10": [
    { "nom": "iPhone 15",  "sotildi": 1250 },
    { "nom": "AirPods",    "sotildi":  980 },
    { "nom": "MacBook",    "sotildi":  640 }
  ]
}
// ✅ Bosh sahifa uchun — bitta so'rov, darhol
db.top_mahsulotlar.findOne({ sana: "2024-01-15" })
So'rov:  1 ms   (tayyor natija)
vs
So'rov: 800 ms  (har safar millionlab buyurtmani hisoblash)

Hisoblash esa orqa fonda — har soatda yoki har kecha bajariladi. Foydalanuvchi kutmaydi.

Qachon ishlatiladi: Ko'p o'qiladigan, lekin kamdan-kam o'zgaradigan statistika — ko'rishlar soni, reyting, oylik hisobot.


Subset Pattern

Muammo

Mahsulot sahifasida 5000 ta sharh bor. Sahifa ochilganda faqat so'nggi 3 tasi ko'rsatiladi. Lekin hamma sharh yuklanadi — isrof.

// ❌ — 5000 ta sharh bitta documentda
{
  "_id": "m1",
  "nom": "iPhone 15",
  "sharhlar": [
    { "matn": "Zo'r!",  "baho": 5 },
    { "matn": "Yaxshi", "baho": 4 }
    // ... 5000 ta
  ]
}

Yechim

Asosiy document da faqat so'nggi 3 ta sharh. Barcha sharhlar — alohida collection da.

// mahsulotlar — faqat so'nggi 3 ta sharh
{
  "_id": "m1",
  "nom": "iPhone 15",
  "narx": 12000000,
  "so_nggi_sharhlar": [
    { "matn": "Zo'r!",  "baho": 5 },
    { "matn": "Yaxshi", "baho": 4 },
    { "matn": "Normal", "baho": 3 }
  ],
  "o_rtacha_baho": 4.2,
  "sharhlar_soni": 5000
}

// sharhlar collection — barcha sharhlar
{ "mahsulot_id": "m1", "matn": "Zo'r!",  "baho": 5 }
{ "mahsulot_id": "m1", "matn": "Yaxshi", "baho": 4 }
// ... 5000 ta
// Birinchi yuklanish — tez, kichik document
db.mahsulotlar.findOne({ _id: "m1" })

// "Ko'proq sharhlar" bosilganda
db.sharhlar.find({ mahsulot_id: "m1" }).sort({ sana: -1 })

Qachon ishlatiladi: Ko'p ma'lumotdan dastlab faqat bir qismi ko'rsatilganda — sharhlar, xabarlar, faollik tarixi.


Xulosa

Pattern     Muammo                          Yechim
─────────   ──────────────────────────      ─────────────────────
Bucket      Millionlab kichik yozuv         Vaqt bo'yicha guruhlash
Outlier     Ba'zi documentlar g'ayritabiiy  Asosiy + overflow
Computed    Tez-tez hisob-kitob             Oldindan hisoblash
Subset      Katta document, oz qism kerak   Asosiy + to'liq alohida

Keyingi dars: 17-dars — Schema Validation — $jsonSchema, validator