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: 0 — backend 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:
{ tags: "mongodb" }bilan qidiring va massiv ichidan qanday topilganini ko’ring.- Xuddi shu maydonni
{ tags: ["mongodb", "baza"] }bilan qidirib, natija bo’sh chiqishini tekshiring, so’ng$allbilan qayta yozing. $pushbilan bitta teg, so’ng$eachbilan ikkitasini qo’shing.- Mavjud tegni
$addToSetbilan qo’shishga urinib,modifiedCount: 0natijasini ko’ring. $pullbilan bitta tegni, keyin$insharti bilan ikkitasini olib tashlang.{ "comments.author": ..., "comments.likes": { $gt: ... } }so’rovini yozing, keyin$elemMatchbilan 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;$eachsiz$pushmassivni ichma-ich joylaydi.$addToSettakrorni tekshiradi — teg va ro’yxat uchun aynan shu kerak.$pullshartga mosini,$popesa chetdagisini olib tashlaydi.- Bir elementga ikki shart qo’yilsa
$elemMatchmajburiy — 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.