ใช่ สามารถทำได้โดยใช้ findAndModify() ซึ่งทำการ Find, Modify, และ Return เอกสารที่อัปเดตแล้วใน Atomic Operation เดียว
สร้างคอลเลกชันและข้อมูลตัวอย่าง
> db.returnResultOfIncementDemo.insertOne({"PlayerScore": 98});
{ "acknowledged": true, "insertedId": ObjectId("5cd3c292edc6604c74817cda") }
แสดงข้อมูลก่อน
> db.returnResultOfIncementDemo.find();
ผลลัพธ์:
{"_id": ObjectId("5cd3c292edc6604c74817cda"), "PlayerScore": 98}
คำสั่ง: Increment และคืนค่าเอกสารใหม่ (new: true)
> db.returnResultOfIncementDemo.findAndModify({
query: {},
update: {$inc: {PlayerScore: 2}},
new: true
});
ผลลัพธ์: คืนเอกสารหลังอัปเดต (PlayerScore = 100)
{"_id": ObjectId("5cd3c292edc6604c74817cda"), "PlayerScore": 100}
พารามิเตอร์สำคัญของ findAndModify
| พารามิเตอร์ | คำอธิบาย | ค่า Default |
|---|---|---|
query | เงื่อนไขค้นหาเอกสาร | {} |
update | Update Operators ($inc, $set, etc.) | Required |
new | true = คืนเอกสารหลังอัปเดต, false = คืนเอกสารก่อนอัปเดต | false |
upsert | true = สร้างใหม่หากไม่พบ | false |
sort | เรียงลำดับหากมีหลายเอกสารตรง Query | - |
fields | Projection (เลือกฟิลด์ที่คืน) | - |
รูปแบบใหม่ (MongoDB 3.2+): findOneAndUpdate
// แทน findAndModify (Deprecated ใน Shell)
db.returnResultOfIncementDemo.findOneAndUpdate(
{},
{$inc: {PlayerScore: 2}},
{returnDocument: "after"} // "after" = new: true, "before" = new: false
);
กรณีใช้งานจริง (Use Cases)
- Counter/Sequence Generator: ดึงหมายเลขถัดไป Atomic
- Queue/Job Processing: Claim Job และ Update Status พร้อมกัน
- Inventory: ลด Stock และเช็คคงเหลือในครั้งเดียว
- Rate Limiting: นับ Request และ Block ถ้าเกิน
ตัวอย่าง Counter แบบ Atomic
function getNextSequence(name) {
var ret = db.counters.findAndModify(
{_id: name},
[],
{$inc: {seq: 1}},
{new: true, upsert: true}
);
return ret.seq;
}
// ใช้งาน
getNextSequence("orderId"); // 1
getNextSequence("orderId"); // 2