5-bo‘lim
So'rovlar va filtr operatorlari
find filtri, solishtirish operatorlari, $in va $nin, $and va $or, $exists va $type, $regex hamda proyeksiya bilan maydon tanlash.
Ushbu bo‘lim mundarijasi
find ikkita argument oladi: nimani topish va qaysi
maydonlarni qaytarish. Bu bobda ikkalasini ham to'liq
ko'rib chiqamiz.
db.kitob.insertMany([
{ _id: 1, nom: "Otkan kunlar", muallif: "Abdulla Qodiriy",
yil: 1926, narx: 85000, nusxa: 12, janr: "tarixiy" },
{ _id: 2, nom: "Mehrobdan chayon", muallif: "Abdulla Qodiriy",
yil: 1929, narx: 72000, nusxa: 5, janr: "tarixiy" },
{ _id: 3, nom: "Kecha va kunduz", muallif: "Cho'lpon",
yil: 1936, narx: 68000, nusxa: 0, janr: "ijtimoiy" },
{ _id: 4, nom: "Navoiy", muallif: "Oybek",
yil: 1944, narx: 95000, nusxa: 8, janr: "tarixiy" },
{ _id: 5, nom: "Ufq", muallif: "Said Ahmad",
yil: 1964, narx: 64000, nusxa: 21, janr: "zamonaviy" },
{ _id: 6, nom: "Sarob", muallif: "Abdulla Qahhor",
yil: 1935, narx: 59000, janr: "ijtimoiy" }
])
Eng oddiy filtr #
Filtr - bu oddiy hujjat. Undagi har bir maydon shart bo'lib xizmat qiladi:
db.kitob.find({ janr: "tarixiy" }, { nom: 1, yil: 1 })
[
{ _id: 1, nom: 'Otkan kunlar', yil: 1926 },
{ _id: 2, nom: 'Mehrobdan chayon', yil: 1929 },
{ _id: 4, nom: 'Navoiy', yil: 1944 }
]
Bir nechta maydon yozilsa, ular VA bilan bog'lanadi:
db.kitob.find({ janr: "tarixiy", muallif: "Abdulla Qodiriy" }, { nom: 1 })
[
{ _id: 1, nom: 'Otkan kunlar' },
{ _id: 2, nom: 'Mehrobdan chayon' }
]
Solishtirish operatorlari #
| Operator | Ma'nosi |
|---|---|
$eq | Teng (odatiy - yozish shart emas) |
$ne | Teng emas |
$gt | Katta |
$gte | Katta yoki teng |
$lt | Kichik |
$lte | Kichik yoki teng |
$in | Ro'yxatdagilardan biri |
$nin | Ro'yxatda yo'q |
db.kitob.find(
{ yil: { $gte: 1930, $lt: 1950 } },
{ nom: 1, yil: 1 }
)
[
{ _id: 3, nom: 'Kecha va kunduz', yil: 1936 },
{ _id: 4, nom: 'Navoiy', yil: 1944 },
{ _id: 6, nom: 'Sarob', yil: 1935 }
]
Bitta maydonga ikkita shart yozilgani e'tiborga loyiq - ular ham VA bilan bog'lanadi.
db.kitob.find(
{ janr: { $in: ["ijtimoiy", "zamonaviy"] } },
{ nom: 1, janr: 1 }
)
[
{ _id: 3, nom: 'Kecha va kunduz', janr: 'ijtimoiy' },
{ _id: 5, nom: 'Ufq', janr: 'zamonaviy' },
{ _id: 6, nom: 'Sarob', janr: 'ijtimoiy' }
]
$or va $and #
db.kitob.find(
{ $or: [ { narx: { $lt: 60000 } }, { nusxa: { $gt: 20 } } ] },
{ nom: 1, narx: 1, nusxa: 1 }
)
[
{ _id: 5, nom: 'Ufq', narx: 64000, nusxa: 21 },
{ _id: 6, nom: 'Sarob', narx: 59000 }
]
$and deyarli hech qachon kerak emasChunki filtrdagi maydonlar allaqachon VA bilan bog'lanadi:
| Yozuv | Bir xilmi |
|---|---|
{ janr: "tarixiy", yil: 1926 } | Ha |
{ $and: [{ janr: "tarixiy" }, { yil: 1926 }] } | Ha - lekin uzunroq |
$and faqat bitta holatda haqiqatan kerak bo'ladi: bir
xil maydonga bir xil operatorni ikki marta qo'llash
zarur bo'lganda.
Masalan "narxi 60 000 dan katta VA 90 000 dan kichik" ni oddiy yozib bo'ladi:
{ narx: { $gt: 60000, $lt: 90000 } }
Lekin "ikki xil $or sharti birga bajarilsin" ni yozish
uchun $and kerak, chunki hujjatda bitta kalit ikki marta
bo'la olmaydi.
$exists va $type #
Oltinchi kitobda nusxa maydoni yo'q:
db.kitob.find({ nusxa: { $exists: false } }, { nom: 1 })
db.kitob.countDocuments({ nusxa: { $exists: true } })
[ { _id: 6, nom: 'Sarob' } ]
5
$ne va $nin maydoni yo'q hujjatlarni ham oladiBu eng ko'p zarar keltiradigan tuzoqlardan biri.
{ nusxa: { $ne: 0 } } shartini "nusxasi bor kitoblar" deb
o'ylash tabiiy. Lekin MongoDB uni shunday tushunadi:
nusxaqiymati 0 ga teng bo'lmagan hujjatlar - shu jumladannusxaumuman yo'q bo'lganlar
Chunki "mavjud bo'lmagan maydon" ham 0 ga teng emas.
To'g'ri yozuv ikkita shartdan iborat:
{ nusxa: { $exists: true, $ne: 0 } }
Yoki muammoni butunlay yo'qotish uchun sxemani qat'iy
qiling: maydon har doim bo'lsin va bo'sh holat 0
bilan yozilsin. 11-bobda buni $jsonSchema bilan qanday
majburlashni ko'ramiz.
Quyidagi ikki so'rov farqini solishtiring:
db.kitob.find({ nusxa: { $ne: 0 } }, { nom: 1, nusxa: 1 })
[
{ _id: 1, nom: 'Otkan kunlar', nusxa: 12 },
{ _id: 2, nom: 'Mehrobdan chayon', nusxa: 5 },
{ _id: 4, nom: 'Navoiy', nusxa: 8 },
{ _id: 5, nom: 'Ufq', nusxa: 21 },
{ _id: 6, nom: 'Sarob' }
]
db.kitob.find({ nusxa: { $exists: true, $ne: 0 } }, { nom: 1, nusxa: 1 })
[
{ _id: 1, nom: 'Otkan kunlar', nusxa: 12 },
{ _id: 2, nom: 'Mehrobdan chayon', nusxa: 5 },
{ _id: 4, nom: 'Navoiy', nusxa: 8 },
{ _id: 5, nom: 'Ufq', nusxa: 21 }
]
Birinchisiga Sarob ham tushdi - garchi uning nusxa
maydoni umuman yo'q bo'lsa ham.
Matn bo'yicha qidirish #
db.kitob.find({ nom: { $regex: /kun/i } }, { nom: 1 })
[ { _id: 1, nom: 'Otkan kunlar' }, { _id: 3, nom: 'Kecha va kunduz' } ]
| Yozuv | Ma'nosi |
|---|---|
/kun/ | Ichida "kun" bo'lsa |
/^kun/ | "kun" bilan boshlansa |
/kun$/ | "kun" bilan tugasa |
/kun/i | Katta-kichik harfga e'tiborsiz |
$regex indeksdan deyarli foydalanmaydiFaqat bitta holat tezkor: ifoda ^ bilan boshlanadigan va
registrga sezgir bo'lsa.
| Ifoda | Indeks ishlaydimi |
|---|---|
/^Otkan/ | Ha - prefiks bo'yicha |
/^Otkan/i | Yo'q - i bayrog'i buzadi |
/kunlar/ | Yo'q - butun to'plam o'qiladi |
/kunlar$/ | Yo'q |
Sabab oddiy: B-tree indeks qiymatlarni boshidan tartiblangan holda saqlaydi. "Boshi ma'lum" bo'lsa, u kerakli joyga sakrab boradi. "Ichida bor" degan savolga esa javob berish uchun hamma qiymatni ko'rish kerak.
Haqiqiy matn qidiruvi uchun matn indeksi yoki $text
ishlatiladi - 15-bobda ko'ramiz.
Proyeksiya - qaysi maydonlar qaytadi #
Ikkinchi argument proyeksiya deb ataladi:
db.kitob.findOne({ _id: 1 }, { nom: 1, narx: 1 })
db.kitob.findOne({ _id: 1 }, { nom: 1, narx: 1, _id: 0 })
db.kitob.findOne({ _id: 1 }, { nusxa: 0, janr: 0, yil: 0 })
{ _id: 1, nom: 'Otkan kunlar', narx: 85000 }
{ nom: 'Otkan kunlar', narx: 85000 }
{
_id: 1,
nom: 'Otkan kunlar',
muallif: 'Abdulla Qodiriy',
narx: 85000
}
Uchta qoida:
| Yozuv | Natija |
|---|---|
{ nom: 1 } | Faqat nom (va _id) |
{ nom: 1, _id: 0 } | Faqat nom |
{ nusxa: 0 } | nusxa dan boshqa hammasi |
_id - yagona istisnoProyeksiyada 1 va 0 ni aralashtirib bo'lmaydi:
db.kitob.find({}, { nom: 1, narx: 0 })
MongoServerError[Location31254]: Cannot do exclusion on
field narx in inclusion projection
Ya'ni yo "faqat shularni ber", yo "shulardan boshqa hammasini ber" - o'rtasi yo'q.
Yagona istisno - _id. U odatiy holda har doim
qaytadi, shuning uchun uni alohida o'chirish mumkin:
{ nom: 1, _id: 0 } to'g'ri yozuv.
Proyeksiya shunchaki qulaylik emas - u tarmoq orqali uzatiladigan hajmni ham kamaytiradi. Katta hujjatlarda bu sezilarli farq beradi.
Sanash #
db.kitob.countDocuments()
db.kitob.countDocuments({ janr: "tarixiy" })
db.kitob.distinct("janr")
db.kitob.distinct("muallif", { janr: "tarixiy" })
6
3
[ 'ijtimoiy', 'tarixiy', 'zamonaviy' ]
[ 'Abdulla Qodiriy', 'Oybek' ]
distinct - takrorlanmagan qiymatlar ro'yxati. SQL dagi
SELECT DISTINCT ning muqobili.
- Bitta maydon bo'yicha oddiy filtr yozing.
- Ikkita shartli filtr yozing va ular qanday bog'langanini ayting.
$gteva$ltbilan oraliq so'rov tuzing.$inbilan ikkita janrni filtrlang.$orbilan ikki xil shartdan birini qanoatlantiruvchilarni toping.$andqachon haqiqatan kerakligini yozing.$nefiltri nega maydoni yo'q hujjatlarni ham olishini tushuntiring.- Uni
$existsbilan to'g'rilang. $regexqaysi holatda indeksdan foydalanishini yozing._idni chiqarmaydigan proyeksiya yozing.
Xulosa #
- Filtr - oddiy hujjat; undagi maydonlar VA bilan bog'lanadi.
- Bitta maydonga bir nechta shart yozish mumkin:
{ yil: { $gte: 1930, $lt: 1950 } }. $inro'yxatdan birini,$ninro'yxatda yo'qini tanlaydi.$ormassiv oladi;$anddeyarli hech qachon kerak emas.$neva$ninmaydoni yo'q hujjatlarni ham qamrab oladi.- To'g'ri yozuv:
{ maydon: { $exists: true, $ne: qiymat } }. $regexfaqat^bilan boshlanadigan, registrga sezgir ifodada indeksdan foydalanadi.- Proyeksiyada
1va0ni aralashtirib bo'lmaydi -_iddan boshqa. - Proyeksiya tarmoq orqali uzatiladigan hajmni ham kamaytiradi.
distincttakrorlanmagan qiymatlar ro'yxatini beradi.
Keyingi bo'limda massiv va ichma-ich hujjatlar ichidan qidirishni 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.