Query operatorlari — $eq, $gt, $lt, $in, $nin, $exists, $regex

~20 daq · MongoDB · CRUD

Muammodan boshlaylik

Oldingi darsda oddiy filterlarni ko'rdik: { shahar: "Toshkent" }. Lekin real hayotda so'rovlar murakkabroq bo'ladi:

  • 18 yoshdan katta va 30 yoshdan kichik talabalar
  • Toshkent yoki Samarqandda yashovchilar
  • Telefon raqami bo'lmaganlar
  • Ismi "A" harfi bilan boshlanadigan foydalanuvchilar
  • Aktiv bo'lmagan yoki o'chirilgan accountlar

Bularning barchasi uchun MongoDB da maxsus query operatorlari bor.


Operatorlar — umumiy ko'rinish

┌─────────────────────────────────────────────────────────────────┐
│  TAQQOSLASH           │  MANTIQIY          │  ELEMENT            │
│  $eq   =              │  $and   VA         │  $exists  mavjudmi  │
│  $ne   !=             │  $or    YOKI       │  $type    tipi      │
│  $gt   >              │  $not   EMAS       │                     │
│  $gte  >=             │  $nor   NA VA NA   │  ARRAY              │
│  $lt   <              │                   │  $all     hammasi   │
│  $lte  <=             │  QIDIRISH          │  $elemMatch         │
│  $in   ichida         │  $regex  pattern   │  $size    uzunlik   │
│  $nin  tashqarida     │  $text   full-text │                     │
└─────────────────────────────────────────────────────────────────┘

Bu darsda eng ko'p ishlatiladiganlari — birin-ketin ko'ramiz.


Taqqoslash operatorlari

$eq — teng

// Ikkalasi bir xil
db.talabalar.find({ yosh: 24 })
db.talabalar.find({ yosh: { $eq: 24 } })

// $eq odatda to'g'ridan-to'g'ri yoziladi — qisqaroq

$ne — teng emas

// Toshkentda bo'lmaganlar
db.talabalar.find({ shahar: { $ne: "Toshkent" } })

// Faol bo'lmaganlar
db.foydalanuvchilar.find({ faol: { $ne: true } })

SQL: WHERE shahar != 'Toshkent'

$gt, $gte, $lt, $lte — kattalik-kichiklik

  $gt  → >     strictly greater than
  $gte → >=    greater than or equal
  $lt  → <     strictly less than
  $lte → <=    less than or equal

  Sonlar:   { narx: { $gt: 50000 } }
  Sanalar:  { sana: { $gt: new Date("2024-01-01") } }
  Matnlar:  { ism: { $gt: "M" } }  ← "M" dan keyin alfavit bo'yicha
// 18 dan katta
db.talabalar.find({ yosh: { $gt: 18 } })

// 18 va 25 oraliq
db.talabalar.find({ yosh: { $gte: 18, $lte: 25 } })

// Narxi 100,000 dan past mahsulotlar
db.mahsulotlar.find({ narx: { $lt: 100000 } })

// 2024-yil yanvardan keyin yaratilganlar
db.postlar.find({ yaratilgan: { $gte: new Date("2024-01-01") } })

SQL bilan:

SELECT * FROM talabalar WHERE yosh > 18;
SELECT * FROM talabalar WHERE yosh BETWEEN 18 AND 25;

$in va $nin — ro'yxatda bor/yo'q

$in — ro'yxatdagi qiymatlardan biri

// Toshkent, Samarqand yoki Namanganda
db.talabalar.find({ shahar: { $in: ["Toshkent", "Samarqand", "Namangan"] } })

// 10A, 10B yoki 10C sinflarda
db.talabalar.find({ sinf: { $in: ["10A", "10B", "10C"] } })

SQL: WHERE shahar IN ('Toshkent', 'Samarqand', 'Namangan')

$nin — ro'yxatdagi qiymatlardan hech biri emas

// Toshkentda ham, Samarqandda ham emas
db.talabalar.find({ shahar: { $nin: ["Toshkent", "Samarqand"] } })

SQL: WHERE shahar NOT IN ('Toshkent', 'Samarqand')

$in — array maydonlarda qudratli

// Massiv maydonida $in — element shu massivda bormi?
db.talabalar.insertMany([
  { ism: "Jasur",  hobbylar: ["dasturlash", "futbol"] },
  { ism: "Malika", hobbylar: ["raqs", "musiqa"] },
  { ism: "Bobur",  hobbylar: ["futbol", "shaxmat"] },
])

// Futbol yoki musiqa hobbysi borlar
db.talabalar.find({ hobbylar: { $in: ["futbol", "musiqa"] } })
// → Jasur (futbol bor), Malika (musiqa bor), Bobur (futbol bor)

Mantiqiy operatorlar

$and — VA (ikkalasi ham)

// Toshkentda VA 20 yoshdan katta
db.talabalar.find({
  $and: [
    { shahar: "Toshkent" },
    { yosh: { $gt: 20 } }
  ]
})

// Yuqoridagi bilan bir xil — qisqa yozuv
db.talabalar.find({ shahar: "Toshkent", yosh: { $gt: 20 } })

$and ni qachon ochiq yozish kerak? Bitta maydon uchun ikki shart:

// ❌ Bu ishlamaydi — ikkinchi $gt birinchini ustidan yozadi
db.mahsulotlar.find({ narx: { $gt: 5000 }, narx: { $lt: 50000 } })

// ✅ Bir xil maydonda ikki shart — $and yoki birlashtirilgan
db.mahsulotlar.find({ narx: { $gt: 5000, $lt: 50000 } })

// Yoki $and bilan
db.mahsulotlar.find({
  $and: [
    { narx: { $gt: 5000 } },
    { narx: { $lt: 50000 } }
  ]
})

$or — YOKI (kamida biri)

// Toshkentda YOKI 18 yoshdan kichik
db.talabalar.find({
  $or: [
    { shahar: "Toshkent" },
    { yosh: { $lt: 18 } }
  ]
})

SQL: WHERE shahar = 'Toshkent' OR yosh < 18

$and va $or birga

// (Toshkent YOKI Samarqand) VA (yosh 20 dan katta)
db.talabalar.find({
  $and: [
    { $or: [{ shahar: "Toshkent" }, { shahar: "Samarqand" }] },
    { yosh: { $gt: 20 } }
  ]
})
Mantiqiy ko'rinish:
  (shahar == "Toshkent" || shahar == "Samarqand")
  &&
  (yosh > 20)

$not — EMAS

// 18 yoshdan katta bo'lmaganlar (18 va undan kichik)
db.talabalar.find({ yosh: { $not: { $gt: 18 } } })
// { yosh <= 18 } bilan bir xil, lekin ba'zan $not aniqroq

// Regex emas
db.users.find({ ism: { $not: /^A/ } })  // ismi A bilan boshlanmaydigan

$nor — NA bu, NA u

// Toshkentda ham emas, 18 dan kichik ham emas
db.talabalar.find({
  $nor: [
    { shahar: "Toshkent" },
    { yosh: { $lt: 18 } }
  ]
})
// → shahar != "Toshkent" AND yosh >= 18

$exists — maydon mavjudmi

Collection:
  Doc A: { ism: "Jasur",  telefon: "+998901234567" }
  Doc B: { ism: "Malika", telefon: null }
  Doc C: { ism: "Bobur"  }  ← telefon yo'q umuman
// telefon maydoni bor (null bo'lsa ham)
db.users.find({ telefon: { $exists: true } })
// → Doc A, Doc B

// telefon maydoni yo'q
db.users.find({ telefon: { $exists: false } })
// → Doc C

// telefon bor VA null emas
db.users.find({ telefon: { $exists: true, $ne: null } })
// → faqat Doc A
┌──────────┬──────────────────┬──────────────────┐
│          │ $exists: true    │ $exists: false   │
├──────────┼──────────────────┼──────────────────┤
│ Doc A    │ ✓ topiladi       │ ✗ topilmaydi     │
│ (qiymat) │                  │                  │
│ Doc B    │ ✓ topiladi       │ ✗ topilmaydi     │
│ (null)   │                  │                  │
│ Doc C    │ ✗ topilmaydi     │ ✓ topiladi       │
│ (yo'q)   │                  │                  │
└──────────┴──────────────────┴──────────────────┘

SQL da bu tushuncha yo'q — SQL da ustun doim bor, faqat NULL yoki emas.


$type — tip tekshirish

// narx string bo'lib qolganlarni topish (noto'g'ri ma'lumot)
db.mahsulotlar.find({ narx: { $type: "string" } })

// narx raqam bo'lganlar
db.mahsulotlar.find({ narx: { $type: "number" } })
// "number" → int32, int64, double, decimal128 — hammasi

// Faqat double
db.mahsulotlar.find({ narx: { $type: "double" } })

// Array bo'lganlar
db.users.find({ telefon: { $type: "array" } })

Amalda $type ko'pincha ma'lumotlar sifatini tekshirish uchun ishlatiladi.


$regex — pattern bilan qidirish

// "jav" so'zi bor documentlar (katta-kichik harfdan qat'iy nazar)
db.postlar.find({ sarlavha: { $regex: "jav", $options: "i" } })

// Qisqaroq yozuv — regex literal
db.postlar.find({ sarlavha: /jav/i })

// Boshidan moslik — ^ anchoring
db.users.find({ ism: /^Jas/ })        // "Jas" bilan boshlanadi
db.users.find({ email: /\.uz$/ })     // ".uz" bilan tugaydi

// Aniq so'z — word boundary
db.postlar.find({ matn: /\bMongoDB\b/ })
Eng ko'p ishlatiladigan bayroq:
  i → katta-kichik harfdan qat'iy nazar (case-insensitive)

SQL bilan:

-- SQL LIKE
SELECT * FROM users WHERE ism LIKE 'Jas%';
SELECT * FROM users WHERE email LIKE '%.uz';

-- SQL REGEXP
SELECT * FROM users WHERE ism REGEXP '^Jas';
// MongoDB
db.users.find({ ism: /^Jas/ })
db.users.find({ email: /\.uz$/ })

Regex — index ishlatmaydi (ehtiyot bo'ling)

// ✅ Boshidan moslik — index ishlatishi mumkin
db.users.find({ ism: /^Jasur/ })

// ❌ O'rtadan yoki oxiridan moslik — full scan
db.users.find({ ism: /asur/ })   // collection ni to'liq o'qiydi
db.users.find({ ism: /ur$/ })    // to'liq scan

Ko'p qidirish kerak bo'lsa — Atlas Search yoki text index (30-dars).


Array operatorlari

$all — massivda barcha qiymatlar bo'lsin

// Futbol ham, shaxmat ham hobbysi borlar
db.talabalar.find({ hobbylar: { $all: ["futbol", "shaxmat"] } })
// → faqat ikkalasi ham bo'lganlar

$size — massiv uzunligi

// Aniq 3 ta hobby borlar
db.talabalar.find({ hobbylar: { $size: 3 } })
// ← faqat aniq son qabul qiladi

$elemMatch — massiv elementi bir necha shartni qondirsin

db.talabalar.insertMany([
  { ism: "Jasur",  baholar: [{ fan: "mat", ball: 90 }, { fan: "fiz", ball: 75 }] },
  { ism: "Malika", baholar: [{ fan: "mat", ball: 60 }, { fan: "fiz", ball: 95 }] },
])

// Matematikadan 80 dan yuqori baho olganlar
db.talabalar.find({
  baholar: {
    $elemMatch: { fan: "mat", ball: { $gt: 80 } }
  }
})
// → faqat Jasur (mat:90)
// Malika topilmaydi — uning mat bali 60

// $elemMatch siz (noto'g'ri)
db.talabalar.find({ "baholar.fan": "mat", "baholar.ball": { $gt: 80 } })
// → Malika ham keladi! Chunki u yerda fan:"mat" bor va 95 ball bor
// (lekin ular turli elementlarda)
$elemMatch nima qiladi:
  Bir element ichida ikki shartni bir vaqtda tekshiradi.

  Jasur: [{ fan:"mat", ball:90 }, { fan:"fiz", ball:75 }]
                ↑ fan="mat" va ball>80 — bitta elementda ✓

  Malika: [{ fan:"mat", ball:60 }, { fan:"fiz", ball:95 }]
                 ↑ fan="mat" lekin ball=60       ↑ ball=95 lekin fan="fiz"
           Bir elementda ikkalasi bir vaqtda yo'q ✗

Bir nechta operator birgalikda — misol

Aktiv mahsulotlar, narxi 50,000 dan 500,000 gacha, "elektronika" yoki "sport" kategoriyasida:

db.mahsulotlar.find({
  faol:       true,
  narx:       { $gte: 50000, $lte: 500000 },
  kategoriya: { $in: ["elektronika", "sport"] }
})

SQL bilan:

SELECT * FROM mahsulotlar
WHERE faol = TRUE
  AND narx BETWEEN 50000 AND 500000
  AND kategoriya IN ('elektronika', 'sport');

Tez-tez uchraydigan xatolar

$in ga massiv emas qiymat berish

// ❌ Xato — $in massiv kutadi
db.users.find({ shahar: { $in: "Toshkent" } })
// MongoServerError: $in needs an array

// ✅ To'g'ri
db.users.find({ shahar: { $in: ["Toshkent"] } })

$and va $or birga yozish

// faol: true VA (Toshkentda YOKI yoshi 18 dan kichik)
db.users.find({
  $and: [
    { faol: true },
    { $or: [{ shahar: "Toshkent" }, { yosh: { $lt: 18 } }] }
  ]
})
// $and ichida $or — aniq va tushunarli

Regex — string qo'shtirnoqda yoki literal

// ✅ Ikkalasi ham to'g'ri
db.users.find({ ism: /^Jas/i })
db.users.find({ ism: { $regex: "^Jas", $options: "i" } })

// ❌ Xato — $regex ga string berilganda flag alohida
db.users.find({ ism: { $regex: "/^Jas/i" } })
// "/^Jas/i" — bu string sifatida tushuniladi, regex emas

Xulosa

┌───────────────────────────────────────────────────────────┐
│  TAQQOSLASH    $eq $ne $gt $gte $lt $lte                  │
│  RO'YXAT       $in $nin                                   │
│  MANTIQIY      $and $or $not $nor                         │
│  ELEMENT       $exists $type                              │
│  MATN          $regex                                     │
│  ARRAY         $all $size $elemMatch                      │
└───────────────────────────────────────────────────────────┘
  • { yosh: { $gt: 18, $lte: 25 } } — bitta maydon, ikki shart
  • $in: [...] — doim massiv bering
  • $exists: true/false — maydon borligini tekshiradi, null ni ham topadi
  • $elemMatch — massiv elementida bir necha shartni birga tekshiradi
  • $regex boshidan moslikda index ishlaydi, o'rtadan moslikda yo'q

Keyingi dars: 9-dars — updateOne, updateMany: $set, $unset, $inc, $push, $pull