6-bo‘lim
Massiv va ichma-ich hujjatlar
Nuqtali yozuv, massiv ichidan qidirish, $all va $size, $elemMatch nima uchun kerak hamda massiv elementini proyeksiya qilish.
Ushbu bo‘lim mundarijasi
Hujjatli bazaning asosiy kuchi shu yerda: bitta hujjat ichida massiv va boshqa hujjatlar bo'lishi mumkin. Lekin ular bo'yicha qidirishning o'z qoidalari bor.
db.kitob.insertMany([
{
_id: 1, nom: "Otkan kunlar",
muallif: { ism: "Abdulla Qodiriy", tugilgan: 1894, shahar: "Toshkent" },
teglar: ["roman", "tarixiy", "klassika"],
baho: [
{ kim: "Malika", ball: 5, yil: 2025 },
{ kim: "Nodira", ball: 4, yil: 2026 }
]
},
{
_id: 2, nom: "Kecha va kunduz",
muallif: { ism: "Cho'lpon", tugilgan: 1897, shahar: "Andijon" },
teglar: ["roman", "ijtimoiy"],
baho: [
{ kim: "Aziza", ball: 5, yil: 2026 },
{ kim: "Malika", ball: 3, yil: 2024 }
]
},
{
_id: 3, nom: "Ufq",
muallif: { ism: "Said Ahmad", tugilgan: 1920, shahar: "Toshkent" },
teglar: ["roman", "zamonaviy"],
baho: [
{ kim: "Kamola", ball: 4, yil: 2025 }
]
},
{
_id: 4, nom: "Sarob",
muallif: { ism: "Abdulla Qahhor", tugilgan: 1907, shahar: "Qoqon" },
teglar: [],
baho: []
}
])
Nuqtali yozuv #
Ichma-ich hujjat ichiga kirish uchun nuqta ishlatiladi. Yo'l qo'shtirnoq ichida yoziladi:
db.kitob.find({ "muallif.shahar": "Toshkent" }, { nom: 1, "muallif.ism": 1 })
[
{ _id: 1, nom: 'Otkan kunlar', muallif: { ism: 'Abdulla Qodiriy' } },
{ _id: 3, nom: 'Ufq', muallif: { ism: 'Said Ahmad' } }
]
Nuqtali yozuv proyeksiyada ham ishlaydi - yuqorida faqat
muallif.ism qaytdi, tugilgan va shahar esa qaytmadi.
Nuqtasiz yozuv butunlay boshqacha ishlaydi:
| Yozuv | Ma'nosi |
|---|---|
{ "muallif.shahar": "Toshkent" } | Ichidagi bitta maydon mos kelsa |
{ muallif: { shahar: "Toshkent" } } | Hujjat aynan shunday bo'lsa |
Ikkinchisi deyarli hech qachon mos kelmaydi, chunki u:
- hamma maydon bir xil bo'lishini,
- tartibi ham bir xil bo'lishini
talab qiladi. { ism: "...", tugilgan: 1894, shahar: "..." }
hujjati { shahar: "Toshkent" } bilan mos kelmaydi.
Amaliy qoida: ichma-ich hujjat bilan ishlaganda deyarli har doim nuqtali yozuv kerak.
db.kitob.countDocuments({ muallif: { shahar: "Toshkent" } })
db.kitob.countDocuments({ "muallif.shahar": "Toshkent" })
0
2
Massiv ichidan qidirish #
Massivga oddiy tenglik yozilsa, MongoDB uni "elementlardan biri" deb tushunadi:
db.kitob.find({ teglar: "tarixiy" }, { nom: 1, teglar: 1 })
[
{
_id: 1,
nom: 'Otkan kunlar',
teglar: [ 'roman', 'tarixiy', 'klassika' ]
}
]
Bu juda qulay: massiv ham, oddiy qiymat ham bir xil yoziladi.
$all, $size va $in #
| Operator | Ma'nosi |
|---|---|
$all | Sanalganlarning hammasi bo'lsin |
$in | Sanalganlardan biri bo'lsa yetarli |
$size | Elementlar soni aynan shuncha |
$exists | Massiv maydoni mavjudmi |
db.kitob.find({ teglar: { $all: ["roman", "tarixiy"] } }, { nom: 1 })
db.kitob.find({ teglar: { $in: ["ijtimoiy", "zamonaviy"] } }, { nom: 1 })
db.kitob.find({ teglar: { $size: 0 } }, { nom: 1 })
[ { _id: 1, nom: 'Otkan kunlar' } ]
[ { _id: 2, nom: 'Kecha va kunduz' }, { _id: 3, nom: 'Ufq' } ]
[ { _id: 4, nom: 'Sarob' } ]
$size oraliq qabul qilmaydi{ teglar: { $size: { $gt: 2 } } } yozuvi ishlamaydi -
$size faqat aniq son oladi.
"Ikkitadan ko'p tegi bor kitoblar" ni topish uchun ikkita yo'l bor:
| Yo'l | Yozuv |
|---|---|
| Indeks orqali tekshirish | { "teglar.2": { $exists: true } } |
| Agregatsiya | $expr bilan $size ni hisoblash |
Birinchisi ayyorona, lekin tez: massiv indeksi noldan
boshlanadi, shuning uchun teglar.2 mavjud bo'lsa - demak
kamida uchta element bor.
Ikkinchisi tushunarliroq, lekin har hujjatni hisoblashni talab qiladi:
{ $expr: { $gt: [ { $size: "$teglar" }, 2 ] } }
db.kitob.find({ "teglar.2": { $exists: true } }, { nom: 1, teglar: 1 })
[
{
_id: 1,
nom: 'Otkan kunlar',
teglar: [ 'roman', 'tarixiy', 'klassika' ]
}
]
$elemMatch - eng muhim operator #
Massiv ichidagi hujjatlar bilan ishlaganda bu operator zarur bo'ladi. Avval usiz sinab ko'ramiz:
db.kitob.find(
{ "baho.ball": 5, "baho.yil": 2026 },
{ nom: 1, baho: 1 }
)
[
{
_id: 1,
nom: 'Otkan kunlar',
baho: [
{ kim: 'Malika', ball: 5, yil: 2025 },
{ kim: 'Nodira', ball: 4, yil: 2026 }
]
},
{
_id: 2,
nom: 'Kecha va kunduz',
baho: [
{ kim: 'Aziza', ball: 5, yil: 2026 },
{ kim: 'Malika', ball: 3, yil: 2024 }
]
}
]
Natijada ikkita kitob chiqdi. Lekin Otkan kunlar ni
diqqat bilan qarang: unda ball: 5 2025-yilda, yil:
2026 esa 4 ball bilan. Ya'ni ikkala shart bitta
bahoda emas, ikki xil bahoda bajarilgan.
Endi $elemMatch bilan:
db.kitob.find(
{ baho: { $elemMatch: { ball: 5, yil: 2026 } } },
{ nom: 1, baho: 1 }
)
[
{
_id: 2,
nom: 'Kecha va kunduz',
baho: [
{ kim: 'Aziza', ball: 5, yil: 2026 },
{ kim: 'Malika', ball: 3, yil: 2024 }
]
}
]
Endi faqat Kecha va kunduz qoldi - unda haqiqatan
bitta bahoda ikkala shart ham bajarilgan.
$elemMatch ni unutmangBu xato hisobotlarda juda ko'p uchraydi va uni sezish qiyin, chunki so'rov ishlaydi - shunchaki noto'g'ri javob beradi.
Qachon kerak:
| Holat | Kerakmi |
|---|---|
| Massivda oddiy qiymatlar, bitta shart | Yo'q |
| Massivda hujjatlar, bitta shart | Yo'q |
| Massivda hujjatlar, ikki yoki undan ko'p shart | Ha |
Oddiy qiymatlar massivi uchun ham bitta holat bor:
{ ball: { $gte: 4, $lte: 5 } }
Bu ham ikkita shartni har xil elementga tarqatishi mumkin. Bitta elementga bog'lash kerak bo'lsa:
{ ball: { $elemMatch: { $gte: 4, $lte: 5 } } }
Massivning bir qismini qaytarish #
Proyeksiyada $elemMatch va $slice ishlatiladi:
db.kitob.find(
{ _id: { $in: [1, 2] } },
{ nom: 1, baho: { $elemMatch: { ball: 5 } } }
)
[
{
_id: 1,
nom: 'Otkan kunlar',
baho: [ { kim: 'Malika', ball: 5, yil: 2025 } ]
},
{
_id: 2,
nom: 'Kecha va kunduz',
baho: [ { kim: 'Aziza', ball: 5, yil: 2026 } ]
}
]
Har hujjatdan faqat birinchi mos keladigan baho qaytdi.
db.kitob.find({ _id: 1 }, { nom: 1, teglar: { $slice: 2 } })
db.kitob.find({ _id: 1 }, { nom: 1, teglar: { $slice: -1 } })
[ { _id: 1, nom: 'Otkan kunlar', teglar: [ 'roman', 'tarixiy' ] } ]
[ { _id: 1, nom: 'Otkan kunlar', teglar: [ 'klassika' ] } ]
| Yozuv | Ma'nosi |
|---|---|
$slice: 2 | Boshidan 2 ta |
$slice: -1 | Oxiridan 1 ta |
$slice: [1, 2] | 1-o'rindan boshlab 2 ta |
Ichma-ich massiv bo'yicha saralash #
db.kitob.find(
{ "baho.ball": { $gte: 4 } },
{ nom: 1, _id: 0 }
).sort({ "muallif.tugilgan": 1 })
[ { nom: 'Otkan kunlar' }, { nom: 'Kecha va kunduz' }, { nom: 'Ufq' } ]
Nuqtali yozuv sort da ham xuddi shunday ishlaydi.
- Nuqtali yozuv bilan ichma-ich maydon bo'yicha qidiring.
- Nuqtasiz butun hujjatni solishtiring va farqni ko'ring.
- Massivga oddiy tenglik qo'yib, nima bo'lishini yozing.
$allva$infarqini misolda ko'rsating.$sizebilan bo'sh massivli hujjatni toping.- "Ikkitadan ko'p element" shartini ikki xil usulda yozing.
- Massiv ichidagi hujjatga ikkita shart qo'ying -
$elemMatchsiz. - Natija nega noto'g'ri ekanini tushuntiring.
- Xuddi shuni
$elemMatchbilan to'g'rilang. $slicebilan massivning oxirgi elementini oling.
Xulosa #
- Ichma-ich hujjatga nuqtali yozuv bilan murojaat qilinadi:
"muallif.shahar". - Nuqtasiz yozuv butun hujjatni aynan solishtiradi - maydon tartibi bilan birga.
- Massivga qo'yilgan oddiy shart "elementlardan biri mos kelsa" degani.
$allhammasini,$inbittasini,$sizeesa aniq sonni talab qiladi.$sizeoraliq qabul qilmaydi -"teglar.2": { $exists: true }yoki$exprishlating.- Massiv ichidagi hujjatlarga ikkita shart qo'yilsa, ular har xil elementga tushishi mumkin.
- Bitta elementga bog'lash uchun
$elemMatchkerak. - Bu xato so'rovni buzmaydi - shunchaki noto'g'ri javob beradi.
- Proyeksiyada
$elemMatchbirinchi mos elementni,$sliceesa bir qismini qaytaradi. - Nuqtali yozuv
find,sortva proyeksiyada bir xil ishlaydi.
Keyingi bo'limda hujjatlarni yangilashni va massiv operatorlarini 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.