MongoDB massiv maydonlar: $push va $pull

Maqolaning bir nechta tegi bor, buyurtmada bir nechta mahsulot, kursda bir nechta talaba. SQL’da bu alohida jadval va JOIN talab qilardi.

MongoDB’da massiv to’g’ridan-to’g’ri hujjat ichida saqlanadi — va u bilan ishlash uchun alohida operatorlar to’plami bor.

Misollar uchun baza:

use blog
db.articles.drop()
db.articles.insertMany([
  {
    title: "MongoDB asoslari",
    tags: ["mongodb", "baza", "backend"],
    views: 1200,
    comments: [
      { author: "Aziz", text: "Foydali maqola", likes: 5 },
      { author: "Malika", text: "Rahmat", likes: 2 }
    ]
  },
  {
    title: "SQL va NoSQL",
    tags: ["sql", "mongodb", "taqqoslash"],
    views: 890,
    comments: [
      { author: "Bekzod", text: "Aniq tushuntirilgan", likes: 8 }
    ]
  },
  {
    title: "JavaScript massivlari",
    tags: ["javascript", "frontend"],
    views: 2100,
    comments: []
  }
])
{
  acknowledged: true,
  insertedIds: {
    '0': ObjectId('671fba1b2c3d4e5f6a7b8c61'),
    '1': ObjectId('671fba1b2c3d4e5f6a7b8c62'),
    '2': ObjectId('671fba1b2c3d4e5f6a7b8c63')
  }
}

Massiv ichida qidirish

Eng kutilmagan xususiyat shu: massiv maydonini oddiy qiymat bilan qidirsangiz, MongoDB elementlar ichidan izlaydi.

db.articles.find({ tags: "mongodb" }, { title: 1, tags: 1, _id: 0 })
[
  { title: 'MongoDB asoslari', tags: [ 'mongodb', 'baza', 'backend' ] },
  { title: 'SQL va NoSQL', tags: [ 'sql', 'mongodb', 'taqqoslash' ] }
]

tags: "mongodb" — “massiv aynan shu qiymatga teng” degani emas, “massivda shu element bor” degani. Bu ataylab shunday qilingan va massivlar bilan ishlashni sezilarli soddalashtiradi.

$all — hammasi bo’lsin

db.articles.find(
  { tags: { $all: ["mongodb", "baza"] } },
  { title: 1, tags: 1, _id: 0 }
)
[ { title: 'MongoDB asoslari', tags: [ 'mongodb', 'baza', 'backend' ] } ]

$in bilan farqi muhim:

Operator Sharti
$in: ["a", "b"] Massivda a yoki b bo’lsin
$all: ["a", "b"] Massivda a va b ikkalasi ham bo’lsin
db.articles.find(
  { tags: { $in: ["javascript", "sql"] } },
  { title: 1, _id: 0 }
)
[ { title: 'SQL va NoSQL' }, { title: 'JavaScript massivlari' } ]

$size — elementlar soni

db.articles.find({ tags: { $size: 2 } }, { title: 1, tags: 1, _id: 0 })
[ { title: 'JavaScript massivlari', tags: [ 'javascript', 'frontend' ] } ]

$push — element qo’shish

db.articles.updateOne(
  { title: "JavaScript massivlari" },
  { $push: { tags: "es6" } }
)
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}
db.articles.findOne({ title: "JavaScript massivlari" }, { title: 1, tags: 1, _id: 0 })
{ title: 'JavaScript massivlari', tags: [ 'javascript', 'frontend', 'es6' ] }

Bir vaqtda bir nechta element qo’shish $each bilan:

db.articles.updateOne(
  { title: "JavaScript massivlari" },
  { $push: { tags: { $each: ["massiv", "metod"] } } }
)
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}
db.articles.findOne({ title: "JavaScript massivlari" }, { tags: 1, _id: 0 })
{ tags: [ 'javascript', 'frontend', 'es6', 'massiv', 'metod' ] }

$addToSet — takrorlanmasin

$push har safar qo’shadi, hatto element allaqachon bo’lsa ham. $addToSet esa takrorni tekshiradi:

db.articles.updateOne(
  { title: "MongoDB asoslari" },
  { $addToSet: { tags: "backend" } }
)
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 0,
  upsertedCount: 0
}

modifiedCount: 0backend allaqachon bor edi, qo’shilmadi.

db.articles.updateOne(
  { title: "MongoDB asoslari" },
  { $addToSet: { tags: "nosql" } }
)
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}

$pull va $pop — olib tashlash

$pull shartga mos elementlarni olib tashlaydi:

db.articles.updateOne(
  { title: "JavaScript massivlari" },
  { $pull: { tags: "metod" } }
)
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}
db.articles.findOne({ title: "JavaScript massivlari" }, { tags: 1, _id: 0 })
{ tags: [ 'javascript', 'frontend', 'es6', 'massiv' ] }

$pull ga operatorli shart ham berish mumkin:

db.articles.updateOne(
  { title: "JavaScript massivlari" },
  { $pull: { tags: { $in: ["es6", "massiv"] } } }
)
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}
db.articles.findOne({ title: "JavaScript massivlari" }, { tags: 1, _id: 0 })
{ tags: [ 'javascript', 'frontend' ] }

$pop esa chetdan bittasini oladi:

Qiymat Nima qiladi
$pop: { tags: 1 } Oxirgi elementni olib tashlaydi
$pop: { tags: -1 } Birinchi elementni olib tashlaydi
db.articles.updateOne(
  { title: "MongoDB asoslari" },
  { $pop: { tags: 1 } }
)
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}
db.articles.findOne({ title: "MongoDB asoslari" }, { tags: 1, _id: 0 })
{ tags: [ 'mongodb', 'baza', 'backend' ] }

Obyektlar massivi va $elemMatch

comments massivida obyektlar bor. Nuqtali yo’l bilan ular ichidan qidirish mumkin:

db.articles.find({ "comments.author": "Aziz" }, { title: 1, _id: 0 })
[ { title: 'MongoDB asoslari' } ]

Endi murakkabroq savol: “Azizning izohi 3 tadan ko’p yoqtirish olgan maqolalar”. Ikki shart bitta izohga tegishli bo’lishi kerak.

Avval yangi izoh qo’shamiz, farq ko’rinishi uchun:

db.articles.updateOne(
  { title: "SQL va NoSQL" },
  { $push: { comments: { author: "Aziz", text: "Qiziq", likes: 1 } } }
)
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}

Endi SQL va NoSQL maqolasida ikki izoh bor: Bekzod (8 like) va Aziz (1 like). Nuqtali yo’l bilan qidiramiz:

db.articles.find(
  { "comments.author": "Aziz", "comments.likes": { $gt: 3 } },
  { title: 1, _id: 0 }
)
[ { title: 'MongoDB asoslari' }, { title: 'SQL va NoSQL' } ]

SQL va NoSQL ham chiqdi — lekin bu noto’g’ri. U yerda Aziz bor (1 like) va 3 dan ko’p like bor (Bekzodda), ammo ular turli izohlarda. Nuqtali yo’l shartlarni bir elementga bog’lamaydi.

Aniq tekshiruv uchun $elemMatch kerak:

db.articles.find(
  { comments: { $elemMatch: { author: "Aziz", likes: { $gt: 3 } } } },
  { title: 1, _id: 0 }
)
[ { title: 'MongoDB asoslari' } ]

Endi faqat bitta maqola qoldi — Azizning o’z izohi 5 like olgan MongoDB asoslari.

Bekzod bilan tekshirsak, uning o’z izohi 8 like olgani uchun natija chiqadi:

db.articles.find(
  { comments: { $elemMatch: { author: "Bekzod", likes: { $gt: 3 } } } },
  { title: 1, _id: 0 }
)
[ { title: 'SQL va NoSQL' } ]

Massiv ichidagi elementni yangilash

Mos kelgan elementni $ belgisi bilan ko’rsatish mumkin:

db.articles.updateOne(
  { title: "MongoDB asoslari", "comments.author": "Malika" },
  { $set: { "comments.$.text": "Juda foydali maqola" } }
)
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}
db.articles.findOne({ title: "MongoDB asoslari" }, { "comments.author": 1, "comments.text": 1, _id: 0 })
{
  comments: [
    { author: 'Aziz', text: 'Foydali maqola' },
    { author: 'Malika', text: 'Juda foydali maqola' }
  ]
}

$ — filtrda topilgan birinchi mos element o’rnini bildiradi. Shuning uchun filtrda o’sha massiv sharti bo’lishi shart.

Massivni joylash yoki ajratish

Massivni hujjat ichida saqlash har doim ham to’g’ri qaror emas:

Holat Joylash (massiv) Alohida kolleksiya
Elementlar soni cheklangan (5-100) Mos
Elementlar cheksiz o’sadi Mos
Har doim asosiy hujjat bilan o’qiladi Mos
Mustaqil qidiriladi va saralanadi Mos

Amaliy mashq

Yuqoridagi blog bazasida bajaring:

  1. { tags: "mongodb" } bilan qidiring va massiv ichidan qanday topilganini ko’ring.
  2. Xuddi shu maydonni { tags: ["mongodb", "baza"] } bilan qidirib, natija bo’sh chiqishini tekshiring, so’ng $all bilan qayta yozing.
  3. $push bilan bitta teg, so’ng $each bilan ikkitasini qo’shing.
  4. Mavjud tegni $addToSet bilan qo’shishga urinib, modifiedCount: 0 natijasini ko’ring.
  5. $pull bilan bitta tegni, keyin $in sharti bilan ikkitasini olib tashlang.
  6. { "comments.author": ..., "comments.likes": { $gt: ... } } so’rovini yozing, keyin $elemMatch bilan qayta yozib natijalarni solishtiring.

6-qadam eng muhimi: bu farq jimgina noto’g’ri natija beradigan kam sonli xatolardan biri.

Qisqacha xulosa

  • Massiv maydonini oddiy qiymat bilan qidirsangiz, elementlar ichidan izlanadi.
  • Massiv qiymat sifatida berilsa, aynan moslik (tartib va son bilan) talab qilinadi.
  • $all — hamma element bo’lsin, $in — bittasi yetarli, $size — aniq son; $each siz $push massivni ichma-ich joylaydi.
  • $addToSet takrorni tekshiradi — teg va ro’yxat uchun aynan shu kerak.
  • $pull shartga mosini, $pop esa chetdagisini olib tashlaydi.
  • Bir elementga ikki shart qo’yilsa $elemMatch majburiy — usiz natija jimgina noto’g’ri chiqadi.
  • Cheksiz o’sadigan ma’lumot massivda emas, alohida kolleksiyada saqlanadi.

Keyingi darsda Node.js bilan ulanish — bazani haqiqiy ilovaga ulash.

Bu dars foydali bo'ldimi?

marta ko'rildi