Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> MongoDB

MongoDB: Insert Array Element หากไม่มี, อัปเดตหากมี (Multiple Conditions) ด้วย bulkWrite

การทำ 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:

  1. Update element ที่มีอยู่: $elemMatch หา element ที่ Marks2=70 และ Marks3=70 แล้ว $set Marks3=96
  2. Insert element ใหม่: $not + $elemMatch หาเอกสารที่ ไม่มี element ตรงเงื่อนไข แล้ว $push element ใหม่
  3. 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