สามารถทำ $pull (ลบ) และ $addToSet (เพิ่มถ้าไม่ซ้ำ) พร้อมกันในคำสั่งเดียวได้โดยใช้ Bulk Operations (initializeOrderedBulkOp())
แนวคิด
$pull- ลบ element ที่ตรงเงื่อนไขออกจากอาร์เรย์$addToSet- เพิ่ม element เข้าอาร์เรย์ถ้ายังไม่มี (unique)- Bulk Op = จับกลุ่มหลาย operation รันพร้อมกัน atomic
ตัวอย่างเต็มรูปแบบ
1. สร้างข้อมูลตัวอย่าง
> db.pullAndAddToSetDemo.insertOne({ "StudentScores": [78, 89, 90] });
2. แสดงข้อมูลก่อน
> db.pullAndAddToSetDemo.find().pretty();
{ "_id" : ObjectId("..."), "StudentScores" : [ 78, 89, 90 ] }
3. Bulk Operation: Pull 90 และ AddToSet 99 พร้อมกัน
> var addAndPull = db.pullAndAddToSetDemo.initializeOrderedBulkOp();
> addAndPull.find({ "StudentScores": 89 }).updateOne({ $addToSet: { "StudentScores": 99 } });
> addAndPull.find({ "StudentScores": 90 }).updateOne({ $pull: { "StudentScores": 90 } });
> addAndPull.execute();
4. ผลลัพธ์การ Execute
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 0,
"nUpserted" : 0,
"nMatched" : 2,
"nModified" : 2,
"nRemoved" : 0,
"upserted" : [ ]
})
5. ตรวจสอบผลลัพธ์สุดท้าย
> db.pullAndAddToSetDemo.find().pretty();
{ "_id" : ObjectId("..."), "StudentScores" : [ 78, 89, 99 ] }
90 ถูกลบ ($pull), 99 ถูกเพิ่ม ($addToSet), 78 และ 89 คงเดิม
วิธีสมัยใหม่ (MongoDB 3.2+): ใช้ bulkWrite()
db.collection.bulkWrite([
{ updateOne: {
filter: { "StudentScores": 89 },
update: { $addToSet: { "StudentScores": 99 } }
}},
{ updateOne: {
filter: { "StudentScores": 90 },
update: { $pull: { "StudentScores": 90 } }
}}
]);
สรุป
- ใช้
initializeOrderedBulkOp()(legacy) หรือbulkWrite()(modern) - แต่ละ operation ใน bulk มี filter และ update แยกกัน
- Ordered = หยุดถ้ามี error, Unordered = รันทุกตัวต่อไป
- Atomic ต่อ operation เดียว แต่ bulk ทั้งหมดไม่ใช่ transaction (เวอร์ชันเก่า)