14-bo‘lim

Hisoblangan maydonlar va shartli ifodalar

$addFields va $set, $cond va $switch, $ifNull, sana operatorlari, $bucket bilan oraliqlarga bo'lish hamda $merge bilan natijani saqlash.

🕑 15 daqiqa o‘qish 📄 745 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. $addFields va $set
  2. $cond - uch qismli shart
  3. $switch - ko'p shartli tanlov
  4. $ifNull - bo'sh qiymatni almashtirish
  5. Sana operatorlari
  6. $bucket - oraliqlarga bo'lish
  7. Matn operatorlari
  8. $merge - natijani saqlash
  9. Xulosa

Agregatsiya faqat guruhlash emas. Uning ichida to'liq hisoblash tili bor: shartlar, sana amallari, matn funksiyalari va massiv operatorlari.

JavaScript
db.buyurtma.insertMany([
  { _id: 1, mijoz: "Husanboy", soni: 3, narx: 85000,
    sana: ISODate("2026-01-12T09:30:00Z"), holat: "yakunlandi" },
  { _id: 2, mijoz: "Malika",   soni: 1, narx: 120000,
    sana: ISODate("2026-01-28T14:00:00Z"), holat: "yakunlandi" },
  { _id: 3, mijoz: "Nodira",   soni: 8, narx: 47000,
    sana: ISODate("2026-02-14T11:15:00Z"), holat: "yolda" },
  { _id: 4, mijoz: "Aziza",    soni: 2, narx: 64000,
    sana: ISODate("2026-02-22T16:45:00Z"), holat: "bekor" },
  { _id: 5, mijoz: "Kamola",   soni: 12, narx: 51000,
    sana: ISODate("2026-03-05T08:00:00Z"), holat: "yakunlandi",
    chegirma: 0.1 },
  { _id: 6, mijoz: "Dilnoza",  soni: 5, narx: 95000,
    sana: ISODate("2026-03-19T19:20:00Z"), holat: "yolda" }
])

$addFields va $set #

$project faqat sanalgan maydonlarni qoldiradi. $addFields esa mavjudlarini saqlab, ustiga yangisini qo'shadi:

JavaScript
db.buyurtma.aggregate([
  { $match: { _id: { $in: [1, 2] } } },
  { $addFields: { jami: { $multiply: ["$soni", "$narx"] } } },
  { $project: { mijoz: 1, soni: 1, narx: 1, jami: 1 } }
])
Natija
[
  { _id: 1, mijoz: 'Husanboy', soni: 3, narx: 85000, jami: 255000 },
  { _id: 2, mijoz: 'Malika', soni: 1, narx: 120000, jami: 120000 }
]

$set - $addFields ning boshqa nomi. Ikkalasi bir xil ishlaydi:

YozuvFarqi
$addFieldsEski nom, hamma versiyada bor
$setYangi nom (4.2 dan), qisqaroq
BosqichSanalmagan maydonlar
$projectTashlanadi
$addFields / $setSaqlanadi

$cond - uch qismli shart #

JavaScript
db.buyurtma.aggregate([
  { $project: {
      mijoz: 1, soni: 1,
      olcham: { $cond: { if: { $gte: ["$soni", 5] },
                         then: "katta", else: "kichik" } }
  } },
  { $sort: { _id: 1 } }
])
Natija
[
  { _id: 1, mijoz: 'Husanboy', soni: 3, olcham: 'kichik' },
  { _id: 2, mijoz: 'Malika', soni: 1, olcham: 'kichik' },
  { _id: 3, mijoz: 'Nodira', soni: 8, olcham: 'katta' },
  { _id: 4, mijoz: 'Aziza', soni: 2, olcham: 'kichik' },
  { _id: 5, mijoz: 'Kamola', soni: 12, olcham: 'katta' },
  { _id: 6, mijoz: 'Dilnoza', soni: 5, olcham: 'katta' }
]

Qisqa yozuvi ham bor - massiv shaklida:

Natija
{ $cond: [ shart, agar_rost, agar_yolgon ] }

$switch - ko'p shartli tanlov #

JavaScript
db.buyurtma.aggregate([
  { $project: {
      mijoz: 1, soni: 1,
      daraja: { $switch: {
        branches: [
          { case: { $gte: ["$soni", 10] }, then: "ulgurji" },
          { case: { $gte: ["$soni", 5] },  then: "orta" },
          { case: { $gte: ["$soni", 2] },  then: "kichik" }
        ],
        default: "yakka"
      } }
  } },
  { $sort: { soni: -1 } }
])
Natija
[
  { _id: 5, mijoz: 'Kamola', soni: 12, daraja: 'ulgurji' },
  { _id: 3, mijoz: 'Nodira', soni: 8, daraja: 'orta' },
  { _id: 6, mijoz: 'Dilnoza', soni: 5, daraja: 'orta' },
  { _id: 1, mijoz: 'Husanboy', soni: 3, daraja: 'kichik' },
  { _id: 4, mijoz: 'Aziza', soni: 2, daraja: 'kichik' },
  { _id: 2, mijoz: 'Malika', soni: 1, daraja: 'yakka' }
]

Shartlar yuqoridan pastga tekshiriladi va birinchi mos kelgani ishlatiladi.

$switch da default ni tashlab ketmang

Agar hech bir shart bajarilmasa va default yozilmagan bo'lsa, MongoDB xato beradi - butun so'rov to'xtaydi:

Natija
MongoServerError: $switch could not find a matching branch
for an input, and no default was specified

Eng yomoni: bu xato ma'lumotga bog'liq. Sinovda hamma hujjat shartlarga tushsa, so'rov ishlaydi. Ishlab chiqarishda esa bitta g'ayrioddiy hujjat butun hisobotni to'xtatib qo'yadi.

Shuning uchun default ni har doim yozing - hatto "bu holat bo'lishi mumkin emas" deb o'ylasangiz ham. default: "nomalum" yozilsa, hisobot ishlaydi va muammo ko'rinadi.

$ifNull - bo'sh qiymatni almashtirish #

Faqat bitta buyurtmada chegirma maydoni bor:

JavaScript
db.buyurtma.aggregate([
  { $project: {
      mijoz: 1,
      chegirma: { $ifNull: ["$chegirma", 0] },
      tolov: { $multiply: [
        "$soni", "$narx",
        { $subtract: [1, { $ifNull: ["$chegirma", 0] }] }
      ] }
  } },
  { $sort: { _id: 1 } }
])
Natija
[
  { _id: 1, mijoz: 'Husanboy', chegirma: 0, tolov: 255000 },
  { _id: 2, mijoz: 'Malika', chegirma: 0, tolov: 120000 },
  { _id: 3, mijoz: 'Nodira', chegirma: 0, tolov: 376000 },
  { _id: 4, mijoz: 'Aziza', chegirma: 0, tolov: 128000 },
  { _id: 5, mijoz: 'Kamola', chegirma: 0.1, tolov: 550800 },
  { _id: 6, mijoz: 'Dilnoza', chegirma: 0, tolov: 475000 }
]

$ifNull siz $multiply null bilan ishlaganda butun natija null bo'lib qolar edi.

Uchta shartli operator, uchta vazifa $cond Ikkita yo'l if / then / else "katta" yoki "kichik" $switch Ko'p yo'l branches + default default siz - xato xavfi $ifNull Bo'shlikni to'ldirish null yoki maydon yo'q o'rniga standart qiymat null bilan hisoblash butun natijani buzadi { $multiply: [3, null] } natijasi null - xato emas, shunchaki bo'sh Shuning uchun hisoblashdan oldin $ifNull bilan himoyalang
Hujjatli bazada maydon yo'qligi odatiy hol - buni har hisoblashda hisobga oling

Sana operatorlari #

OperatorQaytaradi
$year, $month, $dayOfMonthSon
$hour, $minuteSon
$dayOfWeek1 (yakshanba) ... 7 (shanba)
$dateTruncSanani boshiga yaxlitlaydi
$dateToStringMatn ko'rinishiga o'tkazadi
$dateDiffIkki sana orasidagi farq
JavaScript
db.buyurtma.aggregate([
  { $project: {
      mijoz: 1,
      yil: { $year: "$sana" },
      oy: { $month: "$sana" },
      matn: { $dateToString: { format: "%Y-%m-%d", date: "$sana" } }
  } },
  { $sort: { _id: 1 } }
])
Natija
[
  { _id: 1, mijoz: 'Husanboy', yil: 2026, oy: 1, matn: '2026-01-12' },
  { _id: 2, mijoz: 'Malika', yil: 2026, oy: 1, matn: '2026-01-28' },
  { _id: 3, mijoz: 'Nodira', yil: 2026, oy: 2, matn: '2026-02-14' },
  { _id: 4, mijoz: 'Aziza', yil: 2026, oy: 2, matn: '2026-02-22' },
  { _id: 5, mijoz: 'Kamola', yil: 2026, oy: 3, matn: '2026-03-05' },
  { _id: 6, mijoz: 'Dilnoza', yil: 2026, oy: 3, matn: '2026-03-19' }
]

Oylik hisobot uchun $dateTrunc qulay:

JavaScript
db.buyurtma.aggregate([
  { $group: {
      _id: { $dateTrunc: { date: "$sana", unit: "month" } },
      buyurtmalar: { $sum: 1 },
      tushum: { $sum: { $multiply: ["$soni", "$narx"] } }
  } },
  { $sort: { _id: 1 } }
])
Natija
[
  {
    _id: ISODate('2026-01-01T00:00:00.000Z'),
    buyurtmalar: 2,
    tushum: 375000
  },
  {
    _id: ISODate('2026-02-01T00:00:00.000Z'),
    buyurtmalar: 2,
    tushum: 504000
  },
  {
    _id: ISODate('2026-03-01T00:00:00.000Z'),
    buyurtmalar: 2,
    tushum: 1087000
  }
]
Sana operatorlari serverning vaqt mintaqasida ishlaydi

$year, $month va $dateTrunc odatiy holda UTC bo'yicha hisoblaydi.

Toshkent vaqti UTC dan 5 soat oldinda. Ya'ni 1-fevral soat 02:00 da berilgan buyurtma UTC da hali 31-yanvar deb hisoblanadi.

Natijada oylik hisobotdagi bir necha buyurtma noto'g'ri oyga tushadi. Xato kichik ko'rinadi, lekin buxgalteriya hisobotida bu jiddiy muammo.

Yechim - mintaqani ochiq ko'rsatish:

Natija
{ $dateTrunc: { date: "$sana", unit: "month",
                timezone: "Asia/Tashkent" } }

Xuddi shu parametr $year, $month, $dateToString va $dayOfWeek da ham bor.

Qoida: sanani saqlashda har doim UTC, ko'rsatish va guruhlashda esa aniq mintaqa.

Mintaqa bilan va mintaqasiz natijani solishtiring:

JavaScript
db.buyurtma.aggregate([
  { $match: { _id: 5 } },
  { $project: {
      utc_soat: { $hour: "$sana" },
      toshkent_soat: { $hour: { date: "$sana", timezone: "Asia/Tashkent" } }
  } }
])
Natija
[ { _id: 5, utc_soat: 8, toshkent_soat: 13 } ]

$bucket - oraliqlarga bo'lish #

JavaScript
db.buyurtma.aggregate([
  { $bucket: {
      groupBy: "$soni",
      boundaries: [0, 3, 6, 100],
      default: "boshqa",
      output: {
        buyurtmalar: { $sum: 1 },
        mijozlar: { $push: "$mijoz" }
      }
  } }
])
Natija
[
  { _id: 0, buyurtmalar: 2, mijozlar: [ 'Malika', 'Aziza' ] },
  { _id: 3, buyurtmalar: 2, mijozlar: [ 'Husanboy', 'Dilnoza' ] },
  { _id: 6, buyurtmalar: 2, mijozlar: [ 'Nodira', 'Kamola' ] }
]
MaydonMa'nosi
groupByQaysi maydon bo'yicha
boundariesChegaralar - o'sish tartibida
defaultChegaradan tashqaridagilar
outputHar guruhda nima hisoblansin

Chegaralar [0, 3, 6] shunday tushuniladi: 0 <= x < 3, 3 <= x < 6. Ya'ni chap chegara kiradi, o'ng chegara kirmaydi.

Matn operatorlari #

JavaScript
db.buyurtma.aggregate([
  { $match: { _id: { $in: [1, 3] } } },
  { $project: {
      katta: { $toUpper: "$mijoz" },
      uzunlik: { $strLenCP: "$mijoz" },
      bosh_harf: { $substrCP: ["$mijoz", 0, 1] },
      taqdim: { $concat: ["$mijoz", " - ", "$holat"] }
  } }
])
Natija
[
  {
    _id: 1,
    katta: 'HUSANBOY',
    uzunlik: 8,
    bosh_harf: 'H',
    taqdim: 'Husanboy - yakunlandi'
  },
  {
    _id: 3,
    katta: 'NODIRA',
    uzunlik: 6,
    bosh_harf: 'N',
    taqdim: 'Nodira - yolda'
  }
]
$strLenCP va $strLenBytes

O'zbek lotin alifbosida o' va g' belgilari bor, ular UTF-8 da bir necha bayt egallaydi.

OperatorNimani sanaydi
$strLenBytesBaytlar soni
$strLenCPBelgilar soni

"Bog'" so'zi uchun birinchisi 5, ikkinchisi 4 beradi.

Xuddi shu farq kesishda ham bor: $substrBytes belgi o'rtasidan kesib, matnni buzib qo'yishi mumkin.

Qoida oddiy: matn bilan ishlaganda har doim CP variantini ishlating. Bytes variantlari faqat hajmni o'lchash uchun.

$merge - natijani saqlash #

Og'ir hisobotni har safar qayta hisoblash o'rniga, uni alohida to'plamga yozib qo'yish mumkin:

JavaScript
db.buyurtma.aggregate([
  { $group: {
      _id: "$holat",
      buyurtmalar: { $sum: 1 },
      tushum: { $sum: { $multiply: ["$soni", "$narx"] } }
  } },
  { $merge: {
      into: "hisobot",
      whenMatched: "replace",
      whenNotMatched: "insert"
  } }
])
db.hisobot.find().sort({ _id: 1 })
Natija
[
  { _id: 'bekor', buyurtmalar: 1, tushum: 128000 },
  { _id: 'yakunlandi', buyurtmalar: 3, tushum: 987000 },
  { _id: 'yolda', buyurtmalar: 2, tushum: 851000 }
]
BosqichFarqi
$outTo'plamni butunlay almashtiradi
$mergeMavjud hujjatlarni yangilaydi, yangisini qo'shadi

$merge odatda tunda ishga tushadigan hisobotlar uchun ishlatiladi: natija tayyor turadi, foydalanuvchi esa uni darhol oladi.

Amaliy topshiriq
  1. $addFields bilan hisoblangan maydon qo'shing.
  2. $project va $addFields farqini sinab ko'ring.
  3. $cond bilan ikki qiymatli belgi yarating.
  4. $switch bilan uch darajali tasnif tuzing.
  5. default ni olib tashlab, nima bo'lishini yozing.
  6. $ifNull bilan yo'q maydonni nol bilan almashtiring.
  7. $dateToString bilan sanani formatlang.
  8. $dateTrunc ni mintaqa bilan va mintaqasiz solishtiring.
  9. $bucket bilan buyurtmalarni oraliqlarga bo'ling.
  10. $merge bilan hisobotni alohida to'plamga yozing.

Xulosa #

  • $addFields (yoki $set) mavjud maydonlarni saqlab, yangisini qo'shadi.
  • $project esa sanalmagan maydonlarni tashlaydi.
  • $cond ikki yo'lli, $switch esa ko'p yo'lli shart.
  • $switch da default ni har doim yozing - aks holda so'rov ma'lumotga qarab to'xtaydi.
  • $ifNull bo'sh qiymatni almashtiradi - hisoblashdan oldin majburiy.
  • null bilan bajarilgan arifmetika xato emas, lekin natija null bo'ladi.
  • Sana operatorlari odatiy holda UTC bo'yicha ishlaydi.
  • Guruhlash va ko'rsatishda timezone ni ochiq yozing.
  • $bucket qiymatlarni oraliqlarga bo'ladi: chap chegara kiradi, o'ng chegara kirmaydi.
  • Matn bilan ishlaganda $strLenCP va $substrCP - Bytes variantlari emas.

Keyingi bo'limda indekslarni ko'ramiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.