Asosiy kontentga o‘tish
Innovialabs

MongoDB’da agregatsiya: $match, $group, $lookup misollarda

Amaliyot4 daq

Qisqacha

Aggregation pipeline — har biri oldingisining natijasini qayta ishlaydigan bosqichlar zanjiri; $match bilan imkon qadar erta filtrlang, $group bilan guruhlang, $lookup’ni esa kichik ma’lumotlar to‘plamida bajaring.

Aggregation pipeline qanday ishlaydi

Aggregation pipeline — bosqichlar massivi. Hujjatlar ulardan navbat bilan o‘tadi: har bir bosqich oldingisidan oqimni oladi va o‘zgartirilgan oqimni keyingisiga uzatadi. MongoDB’da hisobotlar shunday quriladi: oylar bo‘yicha tushum, eng yaxshi mijozlar, mahsulotlar bo‘yicha savdo.

Asosiy qoida: avval ma’lumotlar hajmini kamaytiring, keyin hisoblang. Filtr va saralash boshida, og‘ir amallar va birlashtirishlar esa oxirida, kichraygan to‘plamda bo‘lsin.

Quyidagi barcha misollar orders kolleksiyasida:

{
  "_id": "...",
  "customerId": "...",
  "status": "paid",
  "createdAt": "2026-01-15T10:00:00Z",
  "total": 420,
  "items": [{ "sku": "A-1", "qty": 2, "price": 150 }, { "sku": "B-7", "qty": 1, "price": 120 }]
}

Asosiy bosqichlar va ularning SQL’dagi analoglari

BosqichNima qiladiSQL’dagi analogi
$matchHujjatlarni filtrlaydiWHERE ($groupdan keyin — HAVING)
$groupGuruhlaydi, yig‘indi, son, o‘rtachani hisoblaydiGROUP BY + agregat funksiyalar
$projectMaydonlarni tanlaydi, nomini o‘zgartiradi, hisoblaydiSELECTdagi maydonlar ro‘yxati
$sort, $limitSaralash va cheklashORDER BY, LIMIT
$unwindMassivni yoyadi: har bir element uchun bitta hujjateng yaqini — bola jadval bilan JOIN
$lookupBoshqa kolleksiyadan hujjatlarni tortib oladiLEFT OUTER JOIN

1-misol: oy bo‘yicha top-10 mijoz

db.orders.aggregate([
  { $match: {
      status: "paid",
      createdAt: { $gte: ISODate("2026-01-01"), $lt: ISODate("2026-02-01") }
  } },
  { $group: { _id: "$customerId", orders: { $sum: 1 }, revenue: { $sum: "$total" } } },
  { $sort: { revenue: -1 } },
  { $limit: 10 },
  { $lookup: { from: "customers", localField: "_id", foreignField: "_id", as: "customer" } },
  { $unwind: "$customer" },
  { $project: { _id: 0, name: "$customer.name", orders: 1, revenue: 1 } }
])

Tartibga e’tibor bering:

  • $match birinchi turadi va indeksdan foydalana oladi.
  • $lookup $limitdan keyin bajariladi, ya’ni oyning barcha mijozlari uchun emas, faqat 10 ta hujjat uchun.
  • Bu yerda $unwind $lookup qaytargan customer massivini oddiy ichki obyektga aylantiradi.

2-misol: $unwind orqali mahsulotlar bo‘yicha savdo

Buyurtma pozitsiyalari items massivida saqlanadi. SKU bo‘yicha savdoni hisoblash uchun massivni yoyish kerak:

db.orders.aggregate([
  { $match: { status: "paid", createdAt: { $gte: ISODate("2026-01-01") } } },
  { $unwind: "$items" },
  { $group: {
      _id: "$items.sku",
      qty: { $sum: "$items.qty" },
      revenue: { $sum: { $multiply: ["$items.qty", "$items.price"] } }
  } },
  { $sort: { revenue: -1 } }
])

$unwind hujjatlar sonini ko‘paytiradi: besh pozitsiyali buyurtma beshta hujjatga aylanadi. Shuning uchun uni $matchdan oldin emas, keyin qo‘ying.

Pipeline’ga yordam beradigan indekslar

  • Indeksdan faqat boshlang‘ich bosqichlar foydalanadi — pipeline boshidagi $match va $sort. $group yoki $unwinddan keyin ma’lumotlar allaqachon xotirada bo‘ladi va kolleksiya indekslari ishlamaydi.
  • Yuqoridagi misollar uchun { status: 1, createdAt: 1 } tarkibiy indeksi mos keladi: avval aniq moslik maydoni, keyin diapazon.
  • $lookup uchun ikkinchi kolleksiyadagi foreignField maydonidagi indeks muhim. _idda u doim bor, boshqa maydonlar uchun uni yarating, aks holda har bir birlashtirish kolleksiyani to‘liq skanerlaydi.
  • Rejani tekshiring: db.orders.explain("executionStats").aggregate([...]). Birinchi bosqichda COLLSCAN ko‘rsangiz, indeks ishlatilmayapti.

Xotira cheklovlari

  • Ma’lumotlarni xotirada ushlab turadigan bosqichlarda ($group, $sort) har bir bosqich uchun xotira limiti bor. U oshib ketsa, so‘rov yo xato beradi, yo ma’lumotlarni diskka yozadi — bu allowDiskUse opsiyasi bilan boshqariladi. Standart xatti-harakat versiyaga bog‘liq, shuning uchun o‘z MongoDB versiyangiz hujjatlarini tekshiring.
  • Natijadagi har bir hujjat 16 MB bilan cheklangan. Agar $lookup minglab bog‘liq hujjatlarni bitta massivga yig‘sa, bu limitdan oshish oson.
  • Diskka yozish xatodan qutqaradi, lekin sekinroq ishlaydi. Eng yaxshi yechim — og‘ir bosqichlardan oldin $match va $project bilan ma’lumotlarni kamaytirish.

Ko‘p uchraydigan xatolar

  • Pipeline boshida butun kolleksiya uchun $lookup — kerak bo‘lmagan joyda qimmat birlashtirish.
  • Filtrlashdan oldin $unwind: ma’lumotlar hajmi bir necha barobar o‘sadi.
  • Hisoblangan maydon bo‘yicha filtr, holbuki uni asl maydon bo‘yicha ertaroq filtrlash mumkin edi.
  • Ish vaqtida asosiy bazada og‘ir hisobotlar. Ular uchun secondary replika yoki $merge orqali alohida kolleksiyaga oldindan hisoblangan ma’lumotlar yaxshiroq.

Ko‘p beriladigan savollar

find hujjatlarni boricha olish uchun mos. Guruhlash, yig‘indi hisoblash, massivlarni yoyish yoki kolleksiyalarni birlashtirish kerak bo‘lsa, aggregation pipeline’dan foydalaning — hisob-kitob ilova kodida emas, serverda bajariladi.

Bunda yordam beramiz

O‘zingiz shug‘ullanmasdan natija olishni istasangiz — biz har kuni shu bilan shug‘ullanamiz.

Loyihani muhokama qilish

Yana o‘qing

G‘oya yoki vazifangiz bormi? Bizga aytib bering

Ish kuni davomida javob beramiz va yechim taklif qilamiz. Konsultatsiya bepul.