การทำ upsert แบบมีเงื่อนไขหลายอย่างใน array (อัปเดตถ้ามี element ตรงเงื่อนไข, insert ใหม่ถ้าไม่มี) ทำได้ด้วย bulkWrite() ที่รวมหลาย operations ในครั้งเดียว
สร้างคอลเลกชันและข้อมูลตัวอย่าง
> db.demo105.insertOne({
_id: '101', Name: 'Chris',
Details: [
{ Marks1: 60, Marks2: 70, Marks3: 70 },
{ Marks1: 70, Marks2: 70, Marks3: 90 }
]
});
{ "acknowledged" : true, "insertedId" : "101" }
แสดงข้อมูลก่อน
> db.demo105.find().pretty();
ผลลัพธ์: _id="101" มี Details 2 elements
Query bulkWrite: อัปเดตถ้ามี, Insert ถ้าไม่มี
> db.demo105.bulkWrite([
// 1. อัปเดต element ที่ Marks2=70 และ Marks3=70 → Marks3=96
{ "updateOne": {
"filter": {
"_id": "101",
"Details": { "$elemMatch": { Marks2: 70, Marks3: 70 } }
},
"update": { "$set": { "Details.$.Marks3": 96 } }
}},
// 2. Insert element ใหม่ หากไม่มี element ที่ Marks2=70 และ Marks3=70
{ "updateOne": {
"filter": {
"_id": "101",
"Details": { "$not": { "$elemMatch": { Marks2: 70, Marks3: 70 } } }
},
"update": { "$push": { "Details": { Marks1: 94, Marks2: 97, Marks3: 99 } } }
}},
// 3. Upsert ทั้งเอกสาร (หาก _id:101 ไม่มีอยู่จริง)
{ "updateOne": {
"filter": { "_id": 101 },
"update": { "$setOnInsert": { "Details": [{ Marks1: 34, Marks2: 67, Marks3: 87 }] } },
"upsert": true
}}
]);
คำอธิบาย 3 Operations:
- Update element ที่มีอยู่: $elemMatch หา element ที่ Marks2=70 และ Marks3=70 แล้ว $set Marks3=96
- Insert element ใหม่: $not + $elemMatch หาเอกสารที่ ไม่มี element ตรงเงื่อนไข แล้ว $push element ใหม่
- Upsert document: หาก _id:101 ไม่มีเลย ให้สร้างใหม่พร้อม Details เริ่มต้น ($setOnInsert รันเฉพาะตอน insert)
ผลลัพธ์ bulkWrite
{
"acknowledged" : true,
"deletedCount" : 0,
"insertedCount" : 0,
"matchedCount" : 2,
"upsertedCount" : 1,
"insertedIds" : {},
"upsertedIds" : { "2" : 101 }
}
ข้อมูลหลังรัน bulkWrite
> db.demo105.find().pretty();
ผลลัพธ์ (มี 2 เอกสาร เพราะ upsert สร้าง _id:101 ใหม่เป็น number):
{ "_id" : "101", "Name" : "Chris", "Details" : [
{ "Marks1" : 60, "Marks2" : 70, "Marks3" : 96 }, // อัปเดต
{ "Marks1" : 70, "Marks2" : 70, "Marks3" : 90 },
{ "Marks1" : 94, "Marks2" : 97, "Marks3" : 99 } // push ใหม่
] }
{ "_id" : 101, "Details" : [ { "Marks1" : 34, "Marks2" : 67, "Marks3" : 87 } ] } // upsert ใหม่
สังเกต: _id "101" (string) และ 101 (number) ถือเป็นคนละค่า → upsert สร้างเอกสารใหม่
ข้อดีของ bulkWrite
- Atomic per operation (แต่ละ operation atomic แยกกัน)
- ลด network round trips
- รวม ordered/unordered execution ได้
- เหมาะสำหรับ batch processing, ETL, migration
ตัวเลือก ordered: bulkWrite(ops, {ordered: false}) รันแบบ parallel ไม่หยุดหากมี error