Ma'lumot turlari — String, Number, Boolean, Date, ObjectId, Array, Object, Null

~20 daq · MongoDB · Kirish va O'rnatish

Muammodan boshlaylik

db.mahsulotlar.insertOne({ narx: "12500" })
db.mahsulotlar.insertOne({ narx: 12500 })

Bu ikki document ko'rinishda o'xshash. Lekin biri string, biri raqam. Farqi? Birinchisida narx > 10000 so'rovi ishlamaydi — string bilan raqamni solishtirish mumkin emas. Sort ham noto'g'ri ishlaydi.

Ma'lumot turini noto'g'ri tanlash — keyinchalik topish qiyin bo'lgan xatolarga olib keladi. Bu darsda har bir turni tushunib olamiz.


MongoDB BSON tiplari — umumiy ko'rinish

┌─────────────────┬──────────────┬───────────────────────────────────┐
│  Tip nomi       │  Misol       │  Qachon ishlatish                 │
├─────────────────┼──────────────┼───────────────────────────────────┤
│  String         │  "Jasur"     │  Matn ma'lumotlari               │
│  Int32          │  24          │  Kichik butun sonlar (-2B..+2B)   │
│  Int64 (Long)   │  9007199...  │  Katta butun sonlar               │
│  Double         │  19.99       │  Kasr sonlar                      │
│  Decimal128     │  19.9900...  │  Moliyaviy aniq kasr              │
│  Boolean        │  true/false  │  Ha/Yo'q holatlari                │
│  Date           │  ISODate(…)  │  Vaqt va sana                    │
│  ObjectId       │  ObjectId(…) │  Unikal identifikator (_id)       │
│  Array          │  [1, 2, 3]   │  Ro'yxat, bir nechta qiymat      │
│  Object         │  { a: 1 }    │  Ichma-ich hujjat                 │
│  Null           │  null        │  Qiymat yo'qligi (qasdan)         │
│  Regex          │  /pattern/   │  Pattern bilan qidirish           │
│  Binary (BinData│  BinData(…)  │  Fayllar, rasmlar (GridFS yaxshi) │
└─────────────────┴──────────────┴───────────────────────────────────┘

Keling, har birini alohida ko'raylik.


1. String

Matnli ma'lumotlar uchun. UTF-8 kodlashda saqlanadi — o'zbek, rus, arab harflari ham ishlaydi.

db.foydalanuvchilar.insertOne({
  ism:     "Jasur",
  familiya: "Karimov",
  shahar:   "Тошкент",     // ← rus harflari
  izoh:     "مرحبا",       // ← arab harflari
  email:    "jasur@mail.uz"
})

String bilan foydali so'rovlar

// Aniq mos
db.users.find({ ism: "Jasur" })

// Regex bilan — "Jas" bilan boshlanadigan
db.users.find({ ism: /^Jas/ })

// Katta-kichik harfdan qat'iy nazar
db.users.find({ ism: /jasur/i })

// $regex operatori (bir xil)
db.users.find({ ism: { $regex: "jasur", $options: "i" } })

SQL bilan solishtiring:

-- SQL
SELECT * FROM users WHERE ism LIKE 'Jas%';
SELECT * FROM users WHERE LOWER(ism) = 'jasur';
// MongoDB
db.users.find({ ism: /^Jas/ })
db.users.find({ ism: /^jasur$/i })

2. Number — uchta tur

Bu ko'pchilikni chalg'itadigan joy. MongoDB da uchta raqam turi bor:

┌─────────────────┬──────────────────────────────┬─────────────────────┐
│  Tur            │  Diapazon                    │  Qaerda ishlatish   │
├─────────────────┼──────────────────────────────┼─────────────────────┤
│  Int32          │  -2,147,483,648              │  Yosh, soni, ball   │
│  (oddiy int)    │  +2,147,483,647              │                     │
├─────────────────┼──────────────────────────────┼─────────────────────┤
│  Int64 / Long   │  -9.2 × 10^18               │  ID, timestamp,     │
│                 │  +9.2 × 10^18               │  juda katta sonlar  │
├─────────────────┼──────────────────────────────┼─────────────────────┤
│  Double         │  ±5.0 × 10^-324 dan          │  Narx, foiz,        │
│  (float)        │  ±1.7 × 10^308 gacha         │  koordinatalar      │
├─────────────────┼──────────────────────────────┼─────────────────────┤
│  Decimal128     │  34 ta aniq raqam            │  Moliya, bank,      │
│                 │  (IEEE 754-2008)             │  valyuta kursi      │
└─────────────────┴──────────────────────────────┴─────────────────────┘

Mongosh da yozilishi

db.mahsulotlar.insertOne({
  soni:      150,                      // ← oddiy son (Int32)
  narx:      19.99,                    // ← kasr (Double)
  aniq_narx: NumberDecimal("19.99"),   // ← moliya uchun aniq kasr
})

Oddiy raqam yozsangiz — 19.99 — MongoDB Double saqlaydi.

Nima uchun Decimal128 muhim?

// Double (IEEE 754 muammosi)
0.1 + 0.2
// 0.30000000000000004  ← noto'g'ri!

// Decimal128
NumberDecimal("0.1") + NumberDecimal("0.2")
// 0.3  ← to'g'ri!

Bank tizimida 0.30000000000000004 so'm farq juda katta muammo. Moliyaviy hisob-kitoblarda doim Decimal128 ishlating.

Raqam bilan so'rovlar

// Tenglik
db.talabalar.find({ yosh: 24 })

// Taqqoslash
db.talabalar.find({ yosh: { $gt: 20 } })     // yosh > 20
db.talabalar.find({ yosh: { $gte: 18 } })    // yosh >= 18
db.talabalar.find({ yosh: { $lt: 30 } })     // yosh < 30
db.talabalar.find({ yosh: { $lte: 25 } })    // yosh <= 25

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

SQL bilan:

-- SQL
SELECT * FROM talabalar WHERE yosh > 20;
SELECT * FROM talabalar WHERE yosh BETWEEN 18 AND 25;
// MongoDB
db.talabalar.find({ yosh: { $gt: 20 } })
db.talabalar.find({ yosh: { $gte: 18, $lte: 25 } })

3. Boolean

Faqat ikki qiymat: true yoki false.

db.foydalanuvchilar.insertOne({
  ism:          "Jasur",
  faol:         true,       // ← aktiv foydalanuvchi
  email_tasdig: false,      // ← email tasdiqlanmagan
  premium:      false
})

Boolean bilan so'rovlar

// Faol foydalanuvchilar
db.foydalanuvchilar.find({ faol: true })

// Email tasdiqlanmaganlar
db.foydalanuvchilar.find({ email_tasdig: false })

SQL bilan:

-- SQL
SELECT * FROM foydalanuvchilar WHERE faol = TRUE;
// MongoDB
db.foydalanuvchilar.find({ faol: true })

Diqqat: "truthy" va "falsy" ishlamaydi

// ❌ Bu XATO — "true" string, boolean emas
db.users.insertOne({ faol: "true" })
db.users.find({ faol: true })    // bu user topilmaydi!

// ✅ To'g'ri
db.users.insertOne({ faol: true })
db.users.find({ faol: true })    // topiladi

4. Date

Vaqt va sana ma'lumotlari uchun. UTC da saqlanadi.

Ichki ko'rinish:
┌──────────────────────────────────────────────────────┐
│  ISODate("2024-03-15T09:30:00.000Z")                │
│           ──────────  ────────────                  │
│              Sana          Vaqt (UTC)               │
└──────────────────────────────────────────────────────┘
db.voqealar.insertOne({
  sarlavha:   "Uchrashuv",
  boshlanish: new Date(),                            // ← hozir
  tugash:     new Date("2024-03-15T18:00:00.000Z"), // ← aniq vaqt
  yaratilgan: ISODate("2024-03-15")                  // ← faqat sana
})

Date bilan so'rovlar

// Bugundan keyin bo'lgan voqealar
db.voqealar.find({
  boshlanish: { $gt: new Date() }
})

// 2024-yil mart oyidagi voqealar
db.voqealar.find({
  boshlanish: {
    $gte: new Date("2024-03-01"),
    $lt:  new Date("2024-04-01")
  }
})

SQL bilan:

-- SQL
SELECT * FROM voqealar WHERE boshlanish > NOW();
SELECT * FROM voqealar
  WHERE boshlanish >= '2024-03-01'
    AND boshlanish < '2024-04-01';

Muhim: Date ni string sifatida saqlamang

// ❌ Yomon — sort ishlamaydi, solishtirish noto'g'ri
{ yaratilgan: "2024-03-15" }

// ✅ Yaxshi — native Date
{ yaratilgan: new Date("2024-03-15") }

String "2024-03-15" va "2023-12-31" ni solishtirsa — string solishtirish "2024" > "2023" to'g'ri, lekin "2024-01-01" va "2023-12-31" da string "2023" < "2024" — bu tasodifan to'g'ri. Ammo murakkab hollarda noto'g'ri natija beradi. Shuning uchun doim native Date ishlating.


5. ObjectId

Avvalgi darsda ko'rdik. Qisqacha eslatma:

ObjectId("64a1f2c3  b4e5f6  a7b8  c9d0e1")
          ────────  ──────  ────  ──────
          Timestamp  Mashina  PID  Random
          (4 bayt)  (3 bayt) (2B)  (3 bayt)
          
Jami: 12 bayt = 24 hex belgi
// Yangi ObjectId yaratish
let id = new ObjectId()
id.toString()      // "64a1f2c3b4e5f6a7b8c9d0e1"
id.getTimestamp()  // ISODate("2024-03-15T09:30:43.000Z")

// _id bo'yicha qidirish
db.talabalar.findOne({ _id: ObjectId("64a1f2c3b4e5f6a7b8c9d0e1") })

// ❌ Bu ishlamaydi — string va ObjectId farqli tiplar
db.talabalar.findOne({ _id: "64a1f2c3b4e5f6a7b8c9d0e1" })

6. Array (Massiv)

Bitta maydonning bir nechta qiymat saqlashi. MongoDB ning kuchli tomonlaridan biri.

db.talabalar.insertOne({
  ism:       "Jasur",
  hobbylar:  ["dasturlash", "futbol", "kitob"],   // ← string array
  baholar:   [85, 92, 78, 95],                    // ← raqam array
  taglar:    [],                                  // ← bo'sh array
})

Array ichida qidirish

MongoDB massiv ichida qidirish uchun maxsus sintaksis talab qilmaydi:

// "futbol" hobbysi bor talabalar
db.talabalar.find({ hobbylar: "futbol" })
// ← MongoDB massiv ichida avtomatik qidiradi

// Bir nechta qiymatdan kamida biri bo'lishi
db.talabalar.find({ hobbylar: { $in: ["futbol", "basketbol"] } })

// Ikkalasi ham bo'lishi
db.talabalar.find({ hobbylar: { $all: ["futbol", "kitob"] } })

// Massiv uzunligi
db.talabalar.find({ hobbylar: { $size: 3 } })

SQL bilan solishtiring — SQL da massiv yo'q, alohida jadval kerak:

-- SQL: alohida jadval va JOIN
SELECT t.*
FROM talabalar t
JOIN hobbylar h ON t.id = h.talaba_id
WHERE h.hobby = 'futbol';
// MongoDB: bitta so'rov, join yo'q
db.talabalar.find({ hobbylar: "futbol" })

Array ichida raqam solishtirish

// Baholardan kamida biri 90 dan yuqori bo'lganlar
db.talabalar.find({ baholar: { $gt: 90 } })
// ← massiv ichidagi har bir element tekshiriladi

// Baholardan kamida biri 80 dan yuqori VA 95 dan past
db.talabalar.find({
  baholar: { $elemMatch: { $gt: 80, $lt: 95 } }
})
// $elemMatch — bitta element ikki shartni qondirishini tekshiradi

7. Object (Embedded Document)

Ichma-ich hujjat — bir document boshqa documentni o'z ichiga oladi.

db.talabalar.insertOne({
  ism: "Jasur",
  manzil: {                 // ← ichma-ich object
    shahar:  "Toshkent",
    tuman:   "Chilonzor",
    pochta:  100301
  },
  diplom: {                 // ← yana bir ichma-ich object
    daraja:    "Bakalavr",
    mutaxassis: "Informatika",
    yil:        2024
  }
})

Ichki maydonlarga so'rov — dot notation

// Chilonzorda yashovchilar
db.talabalar.find({ "manzil.tuman": "Chilonzor" })
//                   ↑↑↑ qo'shtirnoq majburiy

// Informatika mutaxassislar
db.talabalar.find({ "diplom.mutaxassis": "Informatika" })

// Ikki darajali ichki so'rov
db.maktablar.find({ "rektor.lavozim.unvon": "Professor" })

Ichki object ni to'liq solishtirish — ehtiyot bo'ling

// ❌ Bu faqat manzil AYNAN { shahar: "Toshkent" } bo'lganda ishlaydi
// tuman, pochta qo'shilsa — topilmaydi
db.talabalar.find({ manzil: { shahar: "Toshkent" } })

// ✅ To'g'ri — faqat kerakli maydonni tekshiradi
db.talabalar.find({ "manzil.shahar": "Toshkent" })

8. Null

Maydon mavjud lekin qiymati yo'q — maqsadli bo'sh.

db.foydalanuvchilar.insertOne({
  ism:          "Jasur",
  o_chirilgan:  null,      // ← hali o'chirilmagan, lekin maydon bor
  so_nggi_kiris: null      // ← hali kirmagan
})

Null va mavjud emas — farqi bor

┌────────────────────────────────────────────────────────┐
│  Document A: { ism: "Jasur", telefon: null }           │
│  Document B: { ism: "Malika" }                         │
│                          ↑ telefon maydon yo'q         │
└────────────────────────────────────────────────────────┘
// Ikkalasi ham topiladi — null ham, yo'q ham
db.users.find({ telefon: null })
//  → Document A (telefon: null)
//  → Document B (telefon maydoni yo'q)

// Faqat null qiymatlilarni topish
db.users.find({ telefon: { $type: "null" } })
//  → faqat Document A

// Faqat maydoni yo'qlarni topish
db.users.find({ telefon: { $exists: false } })
//  → faqat Document B

// Maydoni borlarni topish (null bo'lsa ham)
db.users.find({ telefon: { $exists: true } })
//  → faqat Document A

SQL bilan:

-- SQL
SELECT * FROM users WHERE telefon IS NULL;
-- SQL da "ustun yo'q" va "NULL" farqlanmaydi

MongoDB da bu farq muhim — shuning uchun $exists va $type operatorlari bor.


Hamma tiplarni bitta documentda ko'rish

db.namuna.insertOne({
  matn:       "Salom",                              // String
  butun:      NumberInt(42),                        // Int32
  kasr:       3.14,                                 // Double
  aniq_kasr:  NumberDecimal("9.99"),                // Decimal128
  mantiqiy:   true,                                 // Boolean
  sana:       new Date(),                           // Date
  id:         new ObjectId(),                       // ObjectId
  royxat:     ["a", "b", "c"],                      // Array
  ichki:      { a: 1, b: 2 },                       // Object
  bosh:       null,                                 // Null
  regex:      /pattern/i                            // RegExp
})

Tip tekshirish — $type operatori

Ma'lumotlar bazasida noto'g'ri tip saqlanib qolgan bo'lsa, topish uchun:

// narx string saqlanganlar — xato ma'lumotlar
db.mahsulotlar.find({ narx: { $type: "string" } })

// narx raqam saqlanganlar — to'g'ri
db.mahsulotlar.find({ narx: { $type: "number" } })

Tez-tez uchraydigan xatolar

Narxni string saqlash

// ❌ String sifatida saqlagan
db.mahsulotlar.insertMany([
  { nom: "Kitob", narx: "25000" },
  { nom: "Qalam", narx: "5000" },
])

db.mahsulotlar.find({ narx: { $gt: 10000 } })
// ← Hech narsa topilmaydi — "25000" string, raqam emas

db.mahsulotlar.find().sort({ narx: 1 })
// ← Noto'g'ri sort: "25000", "5000"  (string sort: "2" < "5")
//   To'g'ri bo'lishi kerak: 5000, 25000 (raqam sort)

Sabab: frontend yoki API dan kelgan ma'lumotlar ba'zan string bo'lib keladi. Saqlashdan oldin tipni tekshiring yoki Mongoose validation ishlating.

Date ni string saqlash

// ❌ String — sort noto'g'ri, oraliq so'rov ishlamaydi
{ yaratilgan: "15-03-2024" }

// ✅ Native Date — sort to'g'ri, oraliq so'rov ishlaydi
{ yaratilgan: new Date("2024-03-15") }

null va undefined farqi

// undefined — BSON da yo'q, MongoDB qabul qilmaydi
db.users.insertOne({ ism: "Jasur", telefon: undefined })
// → telefon maydoni umuman saqlanmaydi

// null — BSON da bor, maxsus qiymat
db.users.insertOne({ ism: "Jasur", telefon: null })
// → { ism: "Jasur", telefon: null }

Mongoose da ham shu qoida: undefined o'tkazmang, null yoki maydonni tashlab keting.


Xulosa

┌─────────────┬────────────────────────────────────────────┐
│  String     │  Matn, UTF-8, regex bilan qidirish        │
│  Int32      │  Kichik butun son (-2B..+2B)               │
│  Double     │  Kasr son, default raqam turi              │
│  Decimal128 │  Moliyaviy aniq kasr — bank, narx          │
│  Boolean    │  true / false — qat'iy tip                 │
│  Date       │  UTC da, native Date ishlating             │
│  ObjectId   │  _id uchun, timestamp o'z ichida           │
│  Array      │  Ro'yxat, ichida qidirish mumkin           │
│  Object     │  Ichma-ich document, dot notation          │
│  Null       │  Qiymat yo'q (maydon yo'q ≠ null)          │
└─────────────┴────────────────────────────────────────────┘

Asosiy qoidalar:

  • Narx, yosh, soni → raqam tur, string emas
  • Sana → new Date(), string emas
  • Moliyaviy hisob → NumberDecimal, Double emas
  • null va maydon yo'qligi — ikki xil holat, $exists bilan farqlash

Keyingi dars: 6-dars — insertOne, insertMany: hujjat qo'shish