bulkWrite — bir nechta operatsiyani birga bajarish
Muammodan boshlaylik
Tasavvur qiling: internet-do'kon. Bir foydalanuvchi 5 ta mahsulot sotib oldi. Siz quyidagilarni qilishingiz kerak:
- Har bir mahsulotning zaxirasini (
soni) kamaytirish - Buyurtmani
buyurtmalarcollection'iga qo'shish - Foydalanuvchining
xaridlar_sonini oshirish
Buni loop bilan qilsangiz — 7 ta alohida so'rov. Har biri tarmoqdan o'tadi, server javob kutadi. 1000 ta buyurtma bir vaqtda kelsa — 7000 ta so'rov. Server cho'kadi.
bulkWrite — bularning barchasini bitta so'rovda yuboradi.
bulkWrite nima?
bulkWrite — turli xil operatsiyalarni (insert, update, delete) bir "paket" ga yig'ib, bitta so'rovda serverga yuborish.
Supermarket kassasiga o'xshang: 10 ta narsa olsangiz, har birini alohida to'lamasiz — hammani birga kassaga qo'yasiz, bir marta to'laysiz. bulkWrite ham shunday.
db.mahsulotlar.bulkWrite([
{ insertOne: { document: { nom: "Olma", narx: 5000 } } },
{ updateOne: { filter: { nom: "Nok" }, update: { $inc: { soni: -1 } } } },
{ deleteOne: { filter: { muddati: { $lt: new Date() } } } }
])
Operatsiya turlari
bulkWrite quyidagi operatsiyalarni qabul qiladi:
db.collection.bulkWrite([
// 1. insertOne — bitta qo'shish
{ insertOne: { document: { nom: "Olma", narx: 5000 } } },
// 2. updateOne — bitta yangilash
{ updateOne: {
filter: { _id: id1 },
update: { $set: { faol: true } },
upsert: false // ixtiyoriy
}},
// 3. updateMany — ko'p yangilash
{ updateMany: {
filter: { kategoriya: "elektronika" },
update: { $inc: { korishlar: 1 } }
}},
// 4. deleteOne — bitta o'chirish
{ deleteOne: { filter: { _id: id2 } } },
// 5. deleteMany — ko'p o'chirish
{ deleteMany: { filter: { eskirgan: true } } },
// 6. replaceOne — to'liq almashtirish
{ replaceOne: {
filter: { _id: id3 },
replacement: { nom: "Yangi nom", narx: 3000 },
upsert: false
}},
])
Amaliy misol — buyurtma qilish
async function buyurtmaQil(foydalanuvchiId, mahsulotlar) {
// mahsulotlar: [{ id, miqdor, narx }, ...]
const operatsiyalar = []
// 1. Har bir mahsulot zaxirasini kamaytirish
for (let mahsulot of mahsulotlar) {
operatsiyalar.push({
updateOne: {
filter: {
_id: mahsulot.id,
soni: { $gte: mahsulot.miqdor } // yetarli zaxira bormi
},
update: {
$inc: { soni: -mahsulot.miqdor } // kamaytiramiz
}
}
})
}
// 2. Foydalanuvchi xaridlar sonini oshirish
operatsiyalar.push({
updateOne: {
filter: { _id: foydalanuvchiId },
update: { $inc: { xaridlar_soni: 1 } }
}
})
let natija = await db.mahsulotlar.bulkWrite(operatsiyalar)
return natija
}
Natija — 7 ta so'rov o'rniga 1 ta so'rov
Tarmoq yuklamasi: 7x kamaydi
Server javob kutish vaqti: 7x kamaydi
Qaytarilgan natija
let natija = await db.mahsulotlar.bulkWrite([...])
// natija:
{
ok: 1,
insertedCount: 2, // qo'shilganlar
upsertedCount: 1, // upsert orqali yaratilganlar
matchedCount: 5, // filtrlarga mos keldi
modifiedCount: 5, // haqiqatan o'zgartirildi
deletedCount: 3, // o'chirildi
insertedIds: { 0: ObjectId("..."), 1: ObjectId("...") },
upsertedIds: { 2: ObjectId("...") }
}
ordered vs unordered
Bu — bulkWrite ning muhim parametri. Xato bo'lganda nima qilishini belgilaydi.
// ordered: true (default) — xato bo'lsa keyingilar bajarilmaydi
db.users.bulkWrite([
{ updateOne: { filter: { _id: id1 }, update: { $set: { a: 1 } } } },
{ updateOne: { filter: { _id: "xato_id" }, update: { $set: { b: 1 } } } }, // xato
{ updateOne: { filter: { _id: id3 }, update: { $set: { c: 1 } } } }, // bu bajarilmaydi
], { ordered: true })
// ordered: false — xato bo'lsa ham keyingilar davom etadi
db.users.bulkWrite([
{ updateOne: { filter: { _id: id1 }, update: { $set: { a: 1 } } } },
{ updateOne: { filter: { _id: "xato_id" }, update: { $set: { b: 1 } } } }, // xato
{ updateOne: { filter: { _id: id3 }, update: { $set: { c: 1 } } } }, // bu bajariladi
], { ordered: false })
ordered: true → tartib muhim, biri xato bo'lsa to'xtaydi
ordered: false → biri xato bo'lsa, qolganlar davom etadi (tezroq)
Qachon qaysinisini tanlash?
ordered: true — operatsiyalar bog'liq bo'lganda
(A qo'shilmasa, B ni yangilamaslik kerak)
ordered: false — operatsiyalar mustaqil bo'lganda
(1000 ta foydalanuvchi notifikatsiyasini yuborish —
biri xato bo'lsa, qolganlari to'xtamasin)
Performance — qachon bulkWrite kerak?
1-10 ta operatsiya → oddiy update/insert yetarli
10-100 ta → bulkWrite sezilarli tezlashtiradi
100+ ta → bulkWrite majburiy
1000+ ta → bulkWrite + batch larga bo'lish
// ✅ Katta ma'lumot uchun batch ga bo'lish
const BATCH_SIZE = 500
for (let i = 0; i < barcha.length; i += BATCH_SIZE) {
const batch = barcha.slice(i, i + BATCH_SIZE)
await db.mahsulotlar.bulkWrite(
batch.map(m => ({
updateOne: {
filter: { _id: m.id },
update: { $set: { yangilangan: new Date() } }
}
})),
{ ordered: false } // tezroq
)
}
Tez-tez uchraydigan xatolar
Bo'sh massiv yuborish
// ❌ operatsiyalar bo'sh bo'lib qolishi mumkin
let ops = []
// ... (ba'zi shartlarda hech narsa qo'shilmadi)
await db.users.bulkWrite(ops) // MongoError: bulkWrite must contain at least 1 operation
// ✅ Tekshirish
if (ops.length > 0) {
await db.users.bulkWrite(ops)
}
ordered: true da bir xato hammani to'xtatadi
// ❌ Birinchi xato — qolgan 999 ta bajarilmaydi
await db.users.bulkWrite(mingTaOperatsiya, { ordered: true })
// ✅ Mustaqil operatsiyalar uchun ordered: false
await db.users.bulkWrite(mingTaOperatsiya, { ordered: false })
Xato ushlanmaydi
// ❌ Xatoliklar e'tiborga olinmaydi
await db.users.bulkWrite(ops)
// ✅ Xatolarni ushlab, qaerda xato bo'lganini bilish
try {
let natija = await db.users.bulkWrite(ops, { ordered: false })
if (natija.hasWriteErrors()) {
console.error("Ba'zi operatsiyalar bajarilmadi:", natija.getWriteErrors())
}
} catch (err) {
console.error("Kritik xato:", err.message)
}
Xulosa
bulkWrite— bir nechta operatsiyani bitta so'rovda yuboradi- 6 ta operatsiya turi:
insertOne,updateOne,updateMany,deleteOne,deleteMany,replaceOne ordered: true— xato bo'lsa to'xtaydi (bog'liq operatsiyalar uchun)ordered: false— xato bo'lsa davom etadi (mustaqil operatsiyalar uchun, tezroq)- 10+ operatsiyada
bulkWrite— sezilarli performance oshiradi - Bo'sh massiv yuborishdan oldin tekshiring
Keyingi dars: 13-dars — Embedding vs Referencing — qachon qaysinisi