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.
Ushbu bo‘lim mundarijasi
Agregatsiya faqat guruhlash emas. Uning ichida to'liq hisoblash tili bor: shartlar, sana amallari, matn funksiyalari va massiv operatorlari.
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:
db.buyurtma.aggregate([
{ $match: { _id: { $in: [1, 2] } } },
{ $addFields: { jami: { $multiply: ["$soni", "$narx"] } } },
{ $project: { mijoz: 1, soni: 1, narx: 1, jami: 1 } }
])
[
{ _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:
| Yozuv | Farqi |
|---|---|
$addFields | Eski nom, hamma versiyada bor |
$set | Yangi nom (4.2 dan), qisqaroq |
| Bosqich | Sanalmagan maydonlar |
|---|---|
$project | Tashlanadi |
$addFields / $set | Saqlanadi |
$cond - uch qismli shart #
db.buyurtma.aggregate([
{ $project: {
mijoz: 1, soni: 1,
olcham: { $cond: { if: { $gte: ["$soni", 5] },
then: "katta", else: "kichik" } }
} },
{ $sort: { _id: 1 } }
])
[
{ _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:
{ $cond: [ shart, agar_rost, agar_yolgon ] }
$switch - ko'p shartli tanlov #
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 } }
])
[
{ _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 ketmangAgar hech bir shart bajarilmasa va default yozilmagan
bo'lsa, MongoDB xato beradi - butun so'rov to'xtaydi:
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:
db.buyurtma.aggregate([
{ $project: {
mijoz: 1,
chegirma: { $ifNull: ["$chegirma", 0] },
tolov: { $multiply: [
"$soni", "$narx",
{ $subtract: [1, { $ifNull: ["$chegirma", 0] }] }
] }
} },
{ $sort: { _id: 1 } }
])
[
{ _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.
Sana operatorlari #
| Operator | Qaytaradi |
|---|---|
$year, $month, $dayOfMonth | Son |
$hour, $minute | Son |
$dayOfWeek | 1 (yakshanba) ... 7 (shanba) |
$dateTrunc | Sanani boshiga yaxlitlaydi |
$dateToString | Matn ko'rinishiga o'tkazadi |
$dateDiff | Ikki sana orasidagi farq |
db.buyurtma.aggregate([
{ $project: {
mijoz: 1,
yil: { $year: "$sana" },
oy: { $month: "$sana" },
matn: { $dateToString: { format: "%Y-%m-%d", date: "$sana" } }
} },
{ $sort: { _id: 1 } }
])
[
{ _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:
db.buyurtma.aggregate([
{ $group: {
_id: { $dateTrunc: { date: "$sana", unit: "month" } },
buyurtmalar: { $sum: 1 },
tushum: { $sum: { $multiply: ["$soni", "$narx"] } }
} },
{ $sort: { _id: 1 } }
])
[
{
_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
}
]
$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:
{ $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:
db.buyurtma.aggregate([
{ $match: { _id: 5 } },
{ $project: {
utc_soat: { $hour: "$sana" },
toshkent_soat: { $hour: { date: "$sana", timezone: "Asia/Tashkent" } }
} }
])
[ { _id: 5, utc_soat: 8, toshkent_soat: 13 } ]
$bucket - oraliqlarga bo'lish #
db.buyurtma.aggregate([
{ $bucket: {
groupBy: "$soni",
boundaries: [0, 3, 6, 100],
default: "boshqa",
output: {
buyurtmalar: { $sum: 1 },
mijozlar: { $push: "$mijoz" }
}
} }
])
[
{ _id: 0, buyurtmalar: 2, mijozlar: [ 'Malika', 'Aziza' ] },
{ _id: 3, buyurtmalar: 2, mijozlar: [ 'Husanboy', 'Dilnoza' ] },
{ _id: 6, buyurtmalar: 2, mijozlar: [ 'Nodira', 'Kamola' ] }
]
| Maydon | Ma'nosi |
|---|---|
groupBy | Qaysi maydon bo'yicha |
boundaries | Chegaralar - o'sish tartibida |
default | Chegaradan tashqaridagilar |
output | Har 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 #
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"] }
} }
])
[
{
_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 $strLenBytesO'zbek lotin alifbosida o' va g' belgilari bor, ular
UTF-8 da bir necha bayt egallaydi.
| Operator | Nimani sanaydi |
|---|---|
$strLenBytes | Baytlar soni |
$strLenCP | Belgilar 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:
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 })
[
{ _id: 'bekor', buyurtmalar: 1, tushum: 128000 },
{ _id: 'yakunlandi', buyurtmalar: 3, tushum: 987000 },
{ _id: 'yolda', buyurtmalar: 2, tushum: 851000 }
]
| Bosqich | Farqi |
|---|---|
$out | To'plamni butunlay almashtiradi |
$merge | Mavjud hujjatlarni yangilaydi, yangisini qo'shadi |
$merge odatda tunda ishga tushadigan hisobotlar uchun
ishlatiladi: natija tayyor turadi, foydalanuvchi esa uni
darhol oladi.
$addFieldsbilan hisoblangan maydon qo'shing.$projectva$addFieldsfarqini sinab ko'ring.$condbilan ikki qiymatli belgi yarating.$switchbilan uch darajali tasnif tuzing.defaultni olib tashlab, nima bo'lishini yozing.$ifNullbilan yo'q maydonni nol bilan almashtiring.$dateToStringbilan sanani formatlang.$dateTruncni mintaqa bilan va mintaqasiz solishtiring.$bucketbilan buyurtmalarni oraliqlarga bo'ling.$mergebilan hisobotni alohida to'plamga yozing.
Xulosa #
$addFields(yoki$set) mavjud maydonlarni saqlab, yangisini qo'shadi.$projectesa sanalmagan maydonlarni tashlaydi.$condikki yo'lli,$switchesa ko'p yo'lli shart.$switchdadefaultni har doim yozing - aks holda so'rov ma'lumotga qarab to'xtaydi.$ifNullbo'sh qiymatni almashtiradi - hisoblashdan oldin majburiy.nullbilan bajarilgan arifmetika xato emas, lekin natijanullbo'ladi.- Sana operatorlari odatiy holda UTC bo'yicha ishlaydi.
- Guruhlash va ko'rsatishda
timezoneni ochiq yozing. $bucketqiymatlarni oraliqlarga bo'ladi: chap chegara kiradi, o'ng chegara kirmaydi.- Matn bilan ishlaganda
$strLenCPva$substrCP-Bytesvariantlari emas.
Keyingi bo'limda indekslarni ko'ramiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
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.