find, findOne — filter, projection, sort, limit, skip

~20 daq · MongoDB · CRUD

Muammodan boshlaylik

Ma'lumotlar bazasida 10,000 ta foydalanuvchi bor. Sizga kerak:

  • Faqat Toshkentliklar
  • Faqat ism va email — telefon, parol ko'rsatma
  • Yoshiga qarab tartiblangan
  • Faqat birinchi 20 tasi

Bu to'rtta talabni SQL da SELECT, WHERE, ORDER BY, LIMIT bilan qilasiz. MongoDB da esa find() ning parametrlari bilan.


find() — asosiy tuzilish

db.<collection>.find(<filter>, <projection>)
                      ↑              ↑
                  Qaysilarni    Qaysi maydonlar
                   topish         ko'rinsin

SQL bilan parallel:

SELECT  ism, email          -- projection
FROM    foydalanuvchilar    -- collection
WHERE   shahar = 'Toshkent' -- filter
db.foydalanuvchilar.find(
  { shahar: "Toshkent" },   // filter
  { ism: 1, email: 1 }      // projection
)

Filter — qaysi documentlar

Bo'sh filter — hammasi

db.talabalar.find()       // barcha documentlar
db.talabalar.find({})     // bir xil — {} bo'sh filter

Aniq qiymat bilan

// Shahar bo'yicha
db.talabalar.find({ shahar: "Toshkent" })

// Bir nechta shart — AND (ikkalasi ham bo'lishi kerak)
db.talabalar.find({ shahar: "Toshkent", sinf: "10A" })

SQL:

SELECT * FROM talabalar WHERE shahar = 'Toshkent';
SELECT * FROM talabalar WHERE shahar = 'Toshkent' AND sinf = '10A';

Solishtirish operatorlari

┌──────────┬──────────────┬──────────────────────────────────┐
│ Operator │  Ma'nosi     │  Misol                           │
├──────────┼──────────────┼──────────────────────────────────┤
│  $eq     │  =           │  { yosh: { $eq: 24 } }           │
│  $ne     │  !=          │  { yosh: { $ne: 24 } }           │
│  $gt     │  >           │  { yosh: { $gt: 18 } }           │
│  $gte    │  >=          │  { yosh: { $gte: 18 } }          │
│  $lt     │  <           │  { yosh: { $lt: 30 } }           │
│  $lte    │  <=          │  { yosh: { $lte: 30 } }          │
│  $in     │  ichida bor  │  { shahar: { $in: ["TK","SQ"] }} │
│  $nin    │  ichida yo'q │  { shahar: { $nin: ["TK"] } }    │
└──────────┴──────────────┴──────────────────────────────────┘
// 18 yoshdan katta
db.talabalar.find({ yosh: { $gt: 18 } })

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

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

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

SQL bilan:

SELECT * FROM talabalar WHERE yosh > 18;
SELECT * FROM talabalar WHERE yosh BETWEEN 18 AND 25;
SELECT * FROM talabalar WHERE shahar IN ('Toshkent', 'Samarqand');
SELECT * FROM talabalar WHERE shahar NOT IN ('Toshkent');

findOne() — birinchi topilgan

find() — barcha mos documentlar (cursor qaytaradi). findOne() — faqat birinchi mos document (object qaytaradi).

db.talabalar.findOne({ ism: "Jasur" })
// → { _id: ObjectId("..."), ism: "Jasur", yosh: 24, ... }
// yoki topilmasa: null
find()    → [doc1, doc2, doc3, ...]   ← cursor
findOne() → doc1                      ← bitta object yoki null

Foydalanish:

// _id bo'yicha — doim findOne yoki find({_id:...})
db.talabalar.findOne({ _id: ObjectId("64a1f2c3b4e5f6a7b8c9d0e1") })

// Birinchi Toshkentlikni topish
db.talabalar.findOne({ shahar: "Toshkent" })

// Topilganini tekshirish
let talaba = db.talabalar.findOne({ ism: "Jasur" })
if (talaba) {
  print("Topildi:", talaba.ism)
} else {
  print("Topilmadi")
}

Projection — qaysi maydonlar ko'rinsin

Har documentda 20 ta maydon bor, lekin sizga faqat 3 tasi kerak. Projection — ortiqcha maydonlarni filtrlaydi.

Projection qoidasi:
  1 → ko'rsat
  0 → yashir

Maydonlarni tanlash (inclusion)

db.talabalar.find(
  {},                              // filter — hammasi
  { ism: 1, yosh: 1, shahar: 1 }  // faqat bu uchta
)
Natija:
{ _id: ObjectId("..."), ism: "Jasur", yosh: 24, shahar: "Toshkent" }
{ _id: ObjectId("..."), ism: "Malika", yosh: 22, shahar: "Samarqand" }

_id doim ko'rinadi — maxsus holat. Uni ham yashirish:

db.talabalar.find(
  {},
  { ism: 1, yosh: 1, _id: 0 }  // ← _id: 0 — yashirish
)
Natija:
{ ism: "Jasur", yosh: 24 }
{ ism: "Malika", yosh: 22 }

Maydonlarni yashirish (exclusion)

// Parol va tokenni yashir, qolganlarni ko'rsat
db.foydalanuvchilar.find(
  {},
  { parol: 0, token: 0 }
)

Inclusion va exclusion aralashtirib bo'lmaydi

// ❌ Xato — ikkalasini aralashtirib bo'lmaydi
db.users.find({}, { ism: 1, parol: 0 })
// MongoServerError: Projection cannot have a mix of inclusion
// and exclusion.

// ✅ Istisno: _id ni alohida 0 qilish mumkin
db.users.find({}, { ism: 1, yosh: 1, _id: 0 })  // ← to'g'ri

Ichki maydonlarni projection bilan olish

// Faqat manzil.shahar ni ko'rsat
db.talabalar.find(
  {},
  { ism: 1, "manzil.shahar": 1 }
)
// → { ism: "Jasur", manzil: { shahar: "Toshkent" } }

SQL bilan:

-- SQL
SELECT ism, yosh, shahar FROM talabalar;
SELECT ism, yosh FROM talabalar;  -- parolsiz
// MongoDB
db.talabalar.find({}, { ism: 1, yosh: 1, shahar: 1 })
db.talabalar.find({}, { parol: 0 })

sort() — tartiblash

db.talabalar.find().sort({ yosh: 1 })   // ↑ kichikdan kattaga (ASC)
db.talabalar.find().sort({ yosh: -1 })  // ↓ kattadan kichikka (DESC)
sort: 1  → A → Z,  1 → 9  (ascending)
sort: -1 → Z → A,  9 → 1  (descending)

Bir nechta maydon bo'yicha sort

// Avval shaharga qarab, keyin yoshga qarab
db.talabalar.find().sort({ shahar: 1, yosh: -1 })
Natija:
{ ism: "Bobur",  shahar: "Namangan",  yosh: 23 }
{ ism: "Zulfiya",shahar: "Namangan",  yosh: 21 }
{ ism: "Malika", shahar: "Samarqand", yosh: 22 }
{ ism: "Jasur",  shahar: "Toshkent",  yosh: 24 }  ← Toshkent: yosh DESC
{ ism: "Sardor", shahar: "Toshkent",  yosh: 23 }

SQL bilan:

-- SQL
SELECT * FROM talabalar ORDER BY shahar ASC, yosh DESC;
// MongoDB
db.talabalar.find().sort({ shahar: 1, yosh: -1 })

limit() va skip() — sahifalash

limit() — nechta qaytarsin

db.talabalar.find().limit(5)    // faqat 5 ta
db.talabalar.find().limit(10)   // faqat 10 ta

skip() — nechtatani o'tkazib yubor

db.talabalar.find().skip(20)    // birinchi 20 tani o'tkazib, qolganlarni

Ikkalasi birgalikda — pagination

100 ta document, sahifada 10 tadan:

  Sahifa 1: skip(0),  limit(10)  → 1-10
  Sahifa 2: skip(10), limit(10)  → 11-20
  Sahifa 3: skip(20), limit(10)  → 21-30
  ...
  Sahifa N: skip((N-1) * 10), limit(10)
let sahifa = 3
let hajm   = 10

db.talabalar
  .find()
  .sort({ ism: 1 })
  .skip((sahifa - 1) * hajm)
  .limit(hajm)

SQL bilan:

-- SQL
SELECT * FROM talabalar
ORDER BY ism ASC
LIMIT 10 OFFSET 20;  -- 3-sahifa
// MongoDB
db.talabalar.find().sort({ ism: 1 }).skip(20).limit(10)

Zanjir — hammasi birgalikda

find() ga sort(), limit(), skip() va projection zanjir shaklida ulanadi:

db.talabalar
  .find(
    { shahar: "Toshkent" },       // filter
    { ism: 1, yosh: 1, _id: 0 }  // projection
  )
  .sort({ yosh: -1 })             // yoshga qarab kamayib
  .skip(0)                        // 1-sahifa
  .limit(10)                      // 10 tadan
Bajarilish tartibi (ichki):
  1. filter  → Toshkentliklarni tanlab
  2. sort    → yoshga qarab tartiblaydi
  3. skip    → birinchi N tani o'tkazadi
  4. limit   → M tani qaytaradi
  5. project → faqat kerakli maydonlarni qoldirib

SQL bilan to'liq parallel:

SELECT ism, yosh
FROM talabalar
WHERE shahar = 'Toshkent'
ORDER BY yosh DESC
LIMIT 10 OFFSET 0;

countDocuments() — sanaymiz

// Hammasi
db.talabalar.countDocuments()

// Shartli
db.talabalar.countDocuments({ shahar: "Toshkent" })

// ❌ Eski — count() deprecated
db.talabalar.count()          // ishlatmang
db.talabalar.find().count()   // ishlatmang

SQL bilan:

SELECT COUNT(*) FROM talabalar WHERE shahar = 'Toshkent';

Amaliy misol — to'liq so'rov

E-commerce saytida: aktiv mahsulotlar, narzi arzondan qimmatga, 2-sahifa, faqat nom va narx:

db.mahsulotlar
  .find(
    { faol: true, narx: { $gte: 10000 } },   // aktiv, narx >= 10,000
    { nom: 1, narx: 1, _id: 0 }              // faqat nom va narx
  )
  .sort({ narx: 1 })                          // arzondan qimmatga
  .skip(20)                                   // 2-sahifa (20 tadan)
  .limit(20)
Natija:
{ nom: "Daftar",  narx: 12000 }
{ nom: "Qalam",   narx: 15000 }
{ nom: "Portfel", narx: 85000 }
...

Tez-tez uchraydigan xatolar

find() cursor ni to'g'ridan-to'g'ri ishlatish

let natija = db.talabalar.find({ shahar: "Toshkent" })

// ❌ Bu ishlaydi lekin cursor ob'ekt qaytadi
print(natija)  // → MongoCursor {...}

// ✅ Massivga aylantirish
let talabalar = db.talabalar.find({ shahar: "Toshkent" }).toArray()
print(talabalar.length)

Node.js/Mongoose da bu muammo yo'q — await bilan massiv keladi.

projection da 1 va 0 aralashtirish

// ❌ Xato — mix of inclusion and exclusion
db.users.find({}, { ism: 1, parol: 0 })

// ✅ Faqat keraklini tanlash
db.users.find({}, { ism: 1, email: 1, _id: 0 })

// ✅ Yoki faqat kerakmaydiganlarni yashirish
db.users.find({}, { parol: 0, token: 0 })

skip() katta sonlarda sekinlashadi

// ❌ skip(50000) — MongoDB 50,000 documentni skanerlaydi, keyin o'tkazadi
db.loglar.find().skip(50000).limit(10)

Katta collectionlarda skip sekin. Cursor-based pagination yaxshiroq (bu haqda keyingi bo'limlarda).

sort() index bo'lmasa sekin

// 1,000,000 document bo'lsa va yosh ga index yo'q bo'lsa:
db.talabalar.find().sort({ yosh: 1 })
// → butun collectionni scan qiladi, keyin sort — juda sekin

Tez-tez sort qiladiganingizga index qo'ying (26-darsda batafsil).


Xulosa

┌─────────────────────────────────────────────────────────────────┐
│  find(<filter>, <projection>)                                   │
│       ↓               ↓                                         │
│  { field: val }    { field: 1/0 }                               │
│  $gt, $lt, $in...  1=ko'rsat, 0=yashir                         │
├─────────────────────────────────────────────────────────────────┤
│  .sort({ field: 1/-1 })   →  1=ASC, -1=DESC                    │
│  .limit(N)                →  N ta qaytaradi                     │
│  .skip(N)                 →  N tani o'tkazib yuboradi           │
│  .countDocuments()        →  soni                              │
├─────────────────────────────────────────────────────────────────┤
│  findOne()  →  bitta object yoki null                           │
│  find()     →  cursor (barcha mos documentlar)                  │
└─────────────────────────────────────────────────────────────────┘
  • find({}) — barchasi; filter bersangiz — mos kelganlar
  • Projection: { a: 1, b: 1 } yoki { c: 0 } — aralashtirib bo'lmaydi
  • Zanjir: .sort().skip().limit() — ketma-ket ulanadi
  • Pagination: skip((page-1) * size).limit(size)

Keyingi dars: 8-dars — Query operatorlari: $eq, $gt, $lt, $in, $nin, $exists, $regex