การอัปเดต field โดยใช้ค่าเดิมของ field นั้นๆ ในการคำนวณค่าใหม่ (เช่นเพิ่ม prefix) ทำได้ด้วย find().forEach() loop ใน Mongo Shell หรือ $function ใน aggregate (MongoDB 4.4+)
สร้างคอลเลกชันและข้อมูลตัวอย่าง
> db.demo115.insertOne({"LastName":"Brown"});
{ "acknowledged" : true, "insertedId" : ObjectId("5e2efe9bd8f64a552dae635a") }
แสดงข้อมูลก่อนอัปเดต
> db.demo115.find();
ผลลัพธ์: { "_id" : ObjectId(...), "LastName" : "Brown" }
Query อัปเดตด้วย forEach Loop (Mongo Shell)
> db.demo115.find({"LastName":"Brown"}).forEach(function(d) {
... db.demo115.update(
... {_id: d._id},
... {$set: {LastName: 'Hello ' + d.LastName}}
... );
... })
คำอธิบาย:
find({"LastName":"Brown"}): หาเอกสารที่ LastName="Brown".forEach(function(d) {...}): วนลูปแต่ละเอกสาร (d = document)d.LastName: เข้าถึงค่าเดิมของ field$set: {LastName: 'Hello ' + d.LastName}: ตั้งค่าใหม่ = "Hello " + ค่าเดิม
ผลลัพธ์หลังอัปเดต
> db.demo115.find();
ผลลัพธ์:
{ "_id" : ObjectId("5e2efe9bd8f64a552dae635a"), "LastName" : "Hello Brown" }
วิธีใหม่: ใช้ $set กับ Aggregation Pipeline (MongoDB 4.2+)
อัปเดตแบบ atomic ใน single operation ไม่ต้อง loop:
db.demo115.updateMany(
{"LastName": "Brown"},
[
{ $set: { LastName: { $concat: ["Hello ", "$LastName"] } } }
]
)
ข้อดี:
- Atomic (ไม่มี race condition)
- เร็วกว่า (single round trip)
- ทำงานบน server side
ใช้ $function สำหรับ Logic ซับซ้อน (MongoDB 4.4+)
db.demo115.updateMany(
{"LastName": "Brown"},
[
{ $set: {
LastName: {
$function: {
body: function(lastName) { return "Hello " + lastName; },
args: ["$LastName"],
lang: "js"
}
}
}}
]
)
ตัวอย่างอื่น: เพิ่ม Suffix, แปลง Case, คำนวณเลข
// เพิ่ม suffix
{$set: {Name: {$concat: ["$Name", " Jr."]}}}
// Uppercase
{$set: {Name: {$toUpper: "$Name"}}}
// คูณค่า
{$set: {Price: {$multiply: ["$Price", 1.1]}}}
สรุป: MongoDB 4.2+ ใช้ update with aggregation pipeline ($set + $concat) แทน forEach loop จะได้ atomic และเร็วกว่า