ข้ามไปยังเนื้อหา

การอัปเดต document

การอัปเดตคือ operation ที่คนมักทำผิดแบบแนบเนียนที่สุด เพราะภาพในหัวที่ดูเป็นธรรมชาติ — “หา document แล้วเขียนทับ field” — ไม่ใช่วิธีที่ MongoDB ทำงาน การอัปเดตประกอบด้วยสอง document: filter ที่เลือก document ที่จะเปลี่ยน และ update document ที่สร้างจาก operator ซึ่งอธิบายการเปลี่ยนแปลง operator คือหัวใจทั้งหมด มันให้คุณบวกเลข ตั้งค่า field ลบ field หรือ push เข้า array โดยไม่แตะส่วนอื่นของ document ส่วนการแทนที่ document ทั้งก้อนใช้เมธอด อีกตัว คือ replaceOne และ driver จะไม่ยอมให้คุณสับสนสองอย่างนี้ (พิสูจน์ด้านล่าง)

เรายังคงแก้ไข members ของห้องสมุดต่อไป ทุก output ด้านล่างจับมาจาก mongo 8.3.11, mongosh 2.11.1 และ Node driver 7.7.0 (แท็บ Python, Go และ Rust รันหนึ่งครั้งในโปรแกรม scratch บน server เดียวกัน) id บนเครื่องของคุณจะต่างออกไป

แต่ละบทเรียน seed ข้อมูลของตัวเอง:

mongosh/update-seed.js
db.members.insertMany([
{ name: "Edsger", joined: 2022, fines: 5 },
{ name: "Linus", joined: 2023, fines: 2 },
{ name: "Margaret", joined: 2023, fines: 0 },
{ name: "Grace", joined: 2024, fines: 0, city: "Arlington", borrowed: ["Compilers"] },
]);
assert.strictEqual(db.members.countDocuments(), 4);

$set เขียนค่าลงใน field ถ้า field มีอยู่จะถูกเขียนทับ ถ้าไม่มีจะถูกสร้าง updateOne ใช้การเปลี่ยนแปลงกับ document แรก ที่ตรงกับ filter แล้วหยุด ที่นี่เราบันทึกว่า Edsger จ่ายค่าปรับครบแล้ว:

mongosh/update-set.js
const res = db.members.updateOne(
{ name: "Edsger" },
{ $set: { fines: 0 } }
);
console.log(res);
console.log(db.members.updateOne({ name: "Edsger" }, { $set: { fines: 0 } })); // the very same update again
console.log(db.members.updateOne({ name: "Nobody" }, { $set: { fines: 0 } })); // no match
assert.strictEqual(res.modifiedCount, 1);

ก่อนอัปเดต Edsger ค้างห้า ({ name: 'Edsger', joined: 2022, fines: 5 }); หลังอัปเดตเปลี่ยนเฉพาะ fines (fines: 0) acknowledgement บอกว่า operation เป็นอย่างไร matchedCount คือจำนวน document ที่ filter พบ; modifiedCount คือจำนวนที่เปลี่ยนจริง สามการเรียกใน shell ด้านบนพิมพ์ (รูปร่าง ack เหมือนกันทั้งสามครั้ง ต่างที่ตัวเลข):

{ acknowledged: true, insertedId: null, matchedCount: 1, modifiedCount: 1, upsertedCount: 0 } <- first run
{ acknowledged: true, insertedId: null, matchedCount: 1, modifiedCount: 0, upsertedCount: 0 } <- same update again
{ acknowledged: true, insertedId: null, matchedCount: 0, modifiedCount: 0, upsertedCount: 0 } <- no such member

ใน Node driver ผลลัพธ์คือ { acknowledged: true, modifiedCount: 1, upsertedId: null, upsertedCount: 0, matchedCount: 1 } และแท็บอื่นเปิดเผยสองตัวเลขเดียวกัน (matched_count, MatchedCount, matched_count) สังเกตบรรทัดที่สอง: รันอัปเดตเดิมซ้ำ matchedCount ยังเป็น 1 แต่ modifiedCount เป็น 0 — document ตรงแต่ไม่มีอะไรต้องเปลี่ยน บรรทัดที่สาม: filter ที่ไม่ตรงอะไรเลย ไม่ใช่ error แค่ matchedCount: 0 ส่วน insertedId: null ใน shell เป็นฟิลด์ตกค้างของ ack การอัปเดต ไม่ต้องสนใจ

$inc บวกตัวเลขเข้ากับ field (ใช้เลขลบเพื่อลบ) มันเป็น atomic ซึ่งเป็นเครื่องมือที่ถูกต้องสำหรับตัวนับและยอดเงิน $set ยังใช้ เพิ่ม field ที่ไม่เคยมีได้ — ที่นี่เราทั้งคิดค่าปรับล่าช้าและประทับปี lastSeen ให้สมาชิกในการเรียกเดียว:

mongosh/update-inc.js
db.members.updateOne(
{ name: "Linus" },
{ $inc: { fines: 3 }, $set: { lastSeen: 2026 } }
);
console.log(db.members.findOne({ name: "Linus" }, { _id: 0 }));
assert.strictEqual(db.members.findOne({ name: "Linus" }).fines, 5);

ก่อนหน้านี้ Linus มีค่าปรับสองและไม่มี field lastSeen; หลังจากนั้นค่าปรับเพิ่มขึ้นสาม และมี field ใหม่ปรากฏ:

{ name: 'Linus', joined: 2023, fines: 5, lastSeen: 2026 }

พฤติกรรมสองข้อที่ควรรู้ พิสูจน์ทั้งคู่: $inc บน field ที่ไม่มีเริ่มจากศูนย์ ({ _id: 1 } -> { _id: 1, visits: 1 }) และ $inc บน field ที่ไม่ใช่ตัวเลขล้มเหลวเสียงดัง:

MongoServerError: Plan executor error during update :: caused by :: Cannot apply $inc to a value of non-numeric type. {_id: ObjectId('...')} has the field 'name' of non-numeric type string

การลบ field ทั้งหมด — ไม่ใช่ตั้งเป็น null แต่ทำให้มันไม่มีอยู่ — ใช้ $unset ค่าที่ให้ถูกเมิน สำคัญแค่ชื่อ field ที่นี่เราถอด field lastSeen ออกจาก Linus:

mongosh/update-unset.js
db.members.updateOne({ name: "Linus" }, { $set: { lastSeen: 2026 } });
db.members.updateOne(
{ name: "Linus" },
{ $unset: { lastSeen: "" } }
);
console.log(db.members.findOne({ name: "Linus" }, { _id: 0 }));
assert.strictEqual("lastSeen" in db.members.findOne({ name: "Linus" }), false);

field lastSeen หายไปอีกครั้ง และไม่มีอะไรอื่นขยับ:

{ name: 'Linus', joined: 2023, fines: 5 }

document มักมี array และคุณไม่ค่อยอยากแทนที่ทั้ง array เพียงเพื่อเพิ่มหรือลบหนึ่งสมาชิก $push ต่อท้ายสมาชิก; $pull ลบทุกสมาชิกที่ตรงกับค่า สมมติสมาชิกแต่ละคนมี array borrowed ของชื่อหนังสือ ก่อนอื่นเราให้ Margaret ยืมหนังสือ:

mongosh/update-push-pull.js
db.members.updateOne(
{ name: "Margaret" },
{ $push: { borrowed: "Compilers" } }
);
console.log(db.members.findOne({ name: "Margaret" }, { _id: 0 }));
db.members.updateOne(
{ name: "Margaret" },
{ $pull: { borrowed: "Compilers" } }
);
console.log(db.members.findOne({ name: "Margaret" }, { _id: 0 }));
assert.deepStrictEqual(Array.from(db.members.findOne({ name: "Margaret" }).borrowed), []);

ถ้า field borrowed ยังไม่มี $push จะสร้างเป็น array หนึ่งสมาชิก และ $pull ลบสมาชิกตามค่า ทิ้ง array ว่าง (ไม่ใช่ field ที่หายไป):

{ name: 'Margaret', joined: 2023, fines: 0, borrowed: [ 'Compilers' ] }
{ name: 'Margaret', joined: 2023, fines: 0, borrowed: [] }

$push บน field ที่ไม่ใช่ array ล้มเหลว: The field 'visits' must be an array but is of type int in document {_id: 1} ญาติสนิทสองตัว: $addToSet ต่อท้ายเฉพาะเมื่อค่ายังไม่มี และ $push กับ $each + $slice เก็บหน้าต่างที่มีขอบเขต — tags: ['a','b'] ที่ push ด้วย { $each: ['c','d','e'], $slice: -3 } กลายเป็น [ 'c', 'd', 'e' ]

updateMany คือการเรียกเดียวกับ updateOne แต่ใช้การเปลี่ยนแปลงกับ ทุก document ที่ filter เลือก ที่นี่เราลดค่าปรับหนึ่งให้ทุกคนที่ค้างชำระอยู่ — สังเกต $inc ค่าลบ:

mongosh/update-many.js
const res = db.members.updateMany(
{ fines: { $gt: 0 } },
{ $inc: { fines: -1 } }
);
console.log(res);
assert.strictEqual(res.matchedCount, res.modifiedCount);

ตัวเลขสะท้อนทุกคนที่ถูกแตะใน operation เดียวนี้ หลังขั้นตอนก่อนหน้า มีเพียง Linus (ค่าปรับ 5) ที่ยังค้างอยู่ ดังนั้น ack คือ matchedCount: 1, modifiedCount: 1 และค่าปรับของเขาลดเหลือ 4 เมื่อมีหลายรายการที่ตรง ทั้งสองตัวเลขคือจำนวน document ที่เปลี่ยน

ใน Compass: เอาเมาส์ชี้ document ใน tab Documents คลิกไอคอนดินสอ แก้ค่าแล้วคลิก Update ตามเอกสาร Compass (modify documents, เรียกอ่านเมื่อ 2026-09-30) มุมมอง List/Table ส่ง findOneAndUpdate (เฉพาะ field ที่คุณเปลี่ยน) ส่วนมุมมอง JSON ส่ง findOneAndReplace (ทั้ง document) — ความต่างระหว่าง update กับ replace เดียวกับด้านล่าง Compass แก้ทีละ document; ถ้าต้องการหลายรายการให้ใช้ updateMany ใน shell ที่ฝังอยู่

กับดักใหญ่สำหรับคนที่มาจากระบบอื่น: ถ้าส่ง document ธรรมดาที่ ไม่มี operator ให้ updateOne ในรูปร่างเดียวกับที่ insert ล่ะ? คำตอบตำราคลาสสิก — “MongoDB ถือเป็นการแทนที่ทั้งก้อน” — ไม่ใช่สิ่งที่ driver สมัยใหม่ทำ ทั้ง mongosh 2.11.1 และ Node driver 7.7.0 ปฏิเสธ:

mongosh/update-bare-document.js
db.people.insertOne({ name: "Grace", joined: 2024, fines: 0, city: "Arlington", borrowed: ["Compilers"] });
// 1. A bare document handed to updateOne: rejected before it reaches the server
let err;
try { db.people.updateOne({ name: "Grace" }, { name: "Grace H.", fines: 9 }); } catch (e) { err = e; }
console.log(err.name + ": " + err.message);
console.log(db.people.findOne({ name: "Grace" }, { _id: 0 })); // untouched
// 2. replaceOne is the method that replaces
console.log(db.people.replaceOne({ name: "Grace" }, { name: "Grace H.", fines: 9 }));
console.log(db.people.findOne({ name: "Grace H." }));
// 3. ...and the two must not be mixed up
let e2, e3;
try { db.people.replaceOne({ name: "Grace H." }, { $set: { a: 1 } }); } catch (e) { e2 = e; }
try { db.people.updateOne({ name: "Grace H." }, { $set: { _id: 5 } }); } catch (e) { e3 = e; }
console.log(e2.name + ": " + e2.message);
console.log(e3.name + ": " + e3.message);
assert.strictEqual(err.message, "Update document requires atomic operators");
MongoInvalidArgumentError: Update document requires atomic operators
{
name: 'Grace',
joined: 2024,
fines: 0,
city: 'Arlington',
borrowed: [ 'Compilers' ]
}
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
_id: ObjectId('6abca92eacc4516d11798c60'),
name: 'Grace H.',
fines: 9
}
MongoInvalidArgumentError: Replacement document must not contain atomic operators
MongoServerError: Plan executor error during update :: caused by :: Performing an update on the path '_id' would modify the immutable field '_id'

ดังนั้น: updateOne/updateMany ต้องการ operator (หรือ aggregation pipeline ด้านล่าง) — document เปล่า ๆ โยน Update document requires atomic operators replaceOne แทนที่ทุกอย่างยกเว้น _id: joined, city และ borrowed หายไป หลังจากนั้น เหลือเพียง name และ fines ซึ่งเป็นเหตุผลที่ไม่ควรหยิบมัน “เพื่อแค่เปลี่ยนชื่อ” _id เปลี่ยนไม่ได้ทั้งสองแบบ ทุก driver ป้องกันแบบเดียวกัน แต่ละตัวด้วยถ้อยคำของตัวเอง — เรารัน update_one/UpdateOne/update_one ที่ส่ง document เปล่า ๆ ในแต่ละภาษา:

Node MongoInvalidArgumentError: Update document requires atomic operators
Python ValueError: update only works with $ operators
Go update document must contain key beginning with '$'
Rust An invalid argument was provided: update document must only contain update modifiers

ตัว server เองยังคงถือ document ที่ไม่มี operator เป็นการแทนที่: การส่งคำสั่งดิบ db.runCommand({ update: "people", updates: [{ q: { name: "Grace" }, u: { name: "Grace H." } }] }) คืน n: 1, nModified: 1, ok: 1 และ document ที่เก็บกลายเป็น { name: 'Grace H.' } — joined และ city หายไป ดังนั้น driver และ mongosh คือสิ่งที่ปกป้องคุณ ถ้าคุณพูดโปรโตคอลเองหรือใช้ driver เก่า อาจยังเจอพฤติกรรมแทนที่โดยไม่ตั้งใจแบบเดิม

array ของ sub-document คือหัวใจของ schema จริง มีสามรูปแบบ positional เพื่อเข้าถึงสมาชิกโดยไม่ต้องรู้ดัชนี (ข้อมูล: Ada มีสองรายการยืม Grace หนึ่ง):

mongosh/update-array-elements.js
db.loans.insertMany([
{ member: "Ada", books: [{ title: "Compilers", renewed: 0 }, { title: "Algorithms", renewed: 1 }] },
{ member: "Grace", books: [{ title: "Compilers", renewed: 2 }] },
]);
// $ : the first element matched by the FILTER
db.loans.updateOne({ member: "Ada", "books.title": "Compilers" }, { $inc: { "books.$.renewed": 1 } });
console.log(db.loans.findOne({ member: "Ada" }, { _id: 0 }).books);
// $[id] with arrayFilters: every element matching a condition
db.loans.updateOne({ member: "Ada" }, { $inc: { "books.$[b].renewed": 10 } }, { arrayFilters: [{ "b.renewed": { $gte: 1 } }] });
console.log(db.loans.findOne({ member: "Ada" }, { _id: 0 }).books);
// $[] : every element
db.loans.updateMany({}, { $set: { "books.$[].seen": true } });
console.log(db.loans.find({}, { _id: 0 }).toArray().map((d) => d.member + ":" + d.books.every((b) => b.seen)));
// $ without an array match in the filter -> error
let err;
try { db.loans.updateOne({ member: "Ada" }, { $inc: { "books.$.renewed": 1 } }); } catch (e) { err = e; }
console.log(err.message);
assert.match(err.message, /positional operator did not find the match/);
[ { title: 'Compilers', renewed: 1 }, { title: 'Algorithms', renewed: 1 } ]
[ { title: 'Compilers', renewed: 11 }, { title: 'Algorithms', renewed: 11 } ]
[ 'Ada:true', 'Grace:true' ]
Plan executor error during update :: caused by :: The positional operator did not find the match needed from the query.

books.$ ต้องการให้ array ปรากฏใน filter ("books.title": "Compilers"); ถ้าไม่มี server ไม่รู้ว่าคุณหมายถึงสมาชิกไหน $[id] + arrayFilters คือรูปแบบทั่วไป; $[] แตะทุกตัว

updateOne คืนจำนวน ไม่ใช่ document เมื่อต้องการ document (คิว หรือตัวนับที่คืนค่าใหม่) ใช้ findOneAndUpdate ซึ่งเป็น atomic — และสังเกตว่าค่าเริ่มต้นคืน document ตามที่เป็น ก่อน อัปเดต:

mongosh/update-find-one-and.js
db.counters.insertOne({ _id: "orders", n: 41 });
const before = db.counters.findOneAndUpdate({ _id: "orders" }, { $inc: { n: 1 } });
const after = db.counters.findOneAndUpdate({ _id: "orders" }, { $inc: { n: 1 } }, { returnDocument: "after" });
const miss = db.counters.findOneAndUpdate({ _id: "nope" }, { $inc: { n: 1 } });
console.log(before, after, miss);
assert.strictEqual(before.n, 41);
assert.strictEqual(after.n, 43);
assert.strictEqual(miss, null);
{ _id: 'orders', n: 41 } { _id: 'orders', n: 43 } null

(Node driver 7.7.0: findOneAndUpdate(filter, update, { returnDocument: "after" }) คืน document เองเลย — { name: 'Grace', joined: 2025 } — และ null เมื่อไม่พบ)

สุดท้าย การอัปเดตยังเป็น aggregation pipeline (array ของ stage) ได้ ซึ่งให้คำนวณ field หนึ่งจากอีก field:

mongosh/update-pipeline.js
db.loans.insertOne({ member: "Alan", books: [{ renewed: 2 }, { renewed: 3 }] });
db.loans.updateOne({ member: "Alan" }, [{ $set: { totalRenewals: { $sum: "$books.renewed" } } }]);
console.log(db.loans.findOne({ member: "Alan" }).totalRenewals);
assert.strictEqual(db.loans.findOne({ member: "Alan" }).totalRenewals, 5);
5
  • กับดัก document เปล่า ฉบับแก้ไข: driver สมัยใหม่ โยน Update document requires atomic operators สำหรับ updateOne(filter, { plain: "document" }) — ไม่ได้แทนที่เงียบ ๆ ถ้าคุณ ต้องการ แทนที่ ให้เรียก replaceOne และจำไว้ว่ามันทิ้งทุก field ที่คุณไม่ได้ใส่
  • matchedCount และ modifiedCount ต่างกันได้ document อาจตรงกับ filter แต่ไม่ถูกแก้ เพราะค่าใหม่เท่าค่าเก่า (matchedCount: 1, modifiedCount: 0 ด้านบน)
  • filter ที่ไม่ตรงอะไรไม่ใช่ error: matchedCount: 0 ตรวจตัวเลขถ้า “ไม่มีอะไรเกิดขึ้น” เป็น bug
  • updateMany ไม่มีขีดจำกัดในตัว — เปลี่ยน ทุก รายการที่ตรง ตรวจ filter ให้ดีก่อนรัน
  • $set สร้าง field ที่ขาด, $unset ลบ และ $inc ใช้ได้แม้ไม่มี field (เริ่มจากศูนย์) แต่ล้มเหลวบน field ที่ไม่ใช่ตัวเลข
  • สอง operator แตะ path เดียวกันในการอัปเดตเดียวไม่ได้: { $set: { fines: 1 }, $inc: { fines: 1 } } ล้มเหลวด้วย Updating the path 'fines' would create a conflict at 'fines'

ผู้ช่วยที่ฝึกจากเอกสาร MongoDB เก่ายังอธิบายพฤติกรรมก่อนที่ driver จะมีตัวป้องกัน:

🐛 หา bug ในโค้ดนี้

// AI comment: "updateOne with a plain document sets those fields and keeps the rest"
async function renameMember(db, id, newName) {
return db.collection("members").updateOne({ _id: id }, { name: newName });
}
เฉลย

ไม่มีครึ่งไหนของ comment นั้นจริง บน mongosh 2.11.1 และ Node driver 7.7.0 การเรียกนี้ โยน MongoInvalidArgumentError: Update document requires atomic operators — request แรกใน production ตาย “การแก้” ที่ล่อใจคือ replaceOne({ _id: id }, { name: newName }) ซึ่งรันได้ แต่แทนที่ทั้ง document: ในการรันด้านบน joined, city และ borrowed หายไป เหลือเฉพาะชื่อใหม่ (และ _id) วิธีแก้ที่ถูกคือห่อการเปลี่ยนใน $set:

app/update-rename-fix.mjs
const members = db.collection("members");
const { insertedId } = await members.insertOne({ name: "Grace", joined: 2024, fines: 0, city: "Arlington" });
let threw = null;
try { await members.updateOne({ _id: insertedId }, { name: "Grace H." }); } catch (e) { threw = e.message; }
console.log("bare document:", threw);
await members.updateOne({ _id: insertedId }, { $set: { name: "Grace H." } });
const after = await members.findOne({ _id: insertedId }, { projection: { _id: 0 } });
console.log("$set :", after);
if (threw !== "Update document requires atomic operators") throw new Error("expected the guard error");
if (after.name !== "Grace H." || after.city !== "Arlington") throw new Error("$set should keep the other fields");
bare document: Update document requires atomic operators
$set : { name: 'Grace H.', joined: 2024, fines: 0, city: 'Arlington' }

การอัปเดตคือ โปรแกรมสำหรับ document หนึ่งใบ: filter เลือกเป้าหมาย และ operator ($set, $inc, $push, …) คือคำสั่งที่ server รันกับ document นั้น แบบ atomic replaceOne เป็นคำกริยา “สลับทั้งก้อน” เพียงตัวเดียว; อย่างอื่นคือการแก้เฉพาะจุด updateMany รันโปรแกรมนั้นหนึ่งครั้งต่อ document ที่ตรง — แต่ละครั้ง atomic ทั้ง batch ไม่ atomic (reference ของ updateMany บอกไว้ตรง ๆ)

ตัวเลือกBenefitCost
updateOneกระทบ document เดียว แม่นยำและคิดตามได้ง่ายว่าเปลี่ยนอะไรต้องเรียกซ้ำหลายครั้งเพื่อเปลี่ยนหลาย document ซึ่งเสียหลาย round trip
updateManyเปลี่ยนหลาย document ในการเรียกเดียว เร็วกว่ามากเมื่อสเกลatomic เฉพาะต่อ document ไม่ใช่ข้าม document — ผู้อ่านอื่นอาจเห็นสถานะที่อัปเดตไปบางส่วนระหว่างที่ทำงาน
อัปเดตด้วย operator ($set บางส่วน)เปลี่ยนเฉพาะ field ที่ต้องการ ส่วนที่เหลือปลอดภัยต้องใส่ operator เสมอ (driver ปฏิเสธ document เปล่า ๆ)
replaceOneสลับทั้ง document ในขั้นเดียว ดีสำหรับการเขียนที่ “document คือแหล่งความจริง”ทิ้งทุก field ที่คุณละไว้ (joined, city, borrowed หายไปด้านบน)
findOneAndUpdateเปลี่ยนและอ่านแบบ atomic ใน round trip เดียวคืน document เก่า เว้นแต่ returnDocument: "after"; ถือ write lock บน document นั้นเหมือนการอัปเดตทั่วไป
  • “updateOne(filter, { plain: 'doc' }) แทนที่ document” — มันโยน Update document requires atomic operators ใน mongosh และ driver Node replaceOne ต่างหากที่แทนที่
  • “replaceOne เป็นวิธีปลอดภัยในการเปลี่ยนหนึ่ง field” — มันลบทุก field ที่คุณละ
  • “อัปเดตที่ไม่เปลี่ยนอะไรคือ error” — matchedCount: 1, modifiedCount: 0 เป็นคำตอบปกติ เช่นเดียวกับ matchedCount: 0
  • “updateMany เป็น transaction atomic เดียว” — atomic เฉพาะการเขียนแต่ละ document; ใช้ multi-document transaction เมื่อต้องการ all-or-nothing
  • “findOneAndUpdate คืน document ใหม่” — โดยค่าเริ่มต้นคืนอันเก่า; ขอ returnDocument: "after"
  • “วน updateOne กับ updateMany เดียวเหมือนกัน” — updateMany ทำใน round trip เดียว

ตัวอย่างจากของจริง

reference ของ updateMany ระบุการรับประกันชัดเจน: “updateMany() modifies each document individually. Each document write is an atomic operation, but updateMany() as a whole is not atomic” และใช้ภายใน distributed transaction ได้ (db.collection.updateMany, เรียกอ่านเมื่อ 2026-09-30)

แท็บ Python/Go/Rust สะท้อนพฤติกรรมที่พิสูจน์แล้วของ shell/Node; แต่ละแท็บถูกรันหนึ่งครั้งในโปรแกรม scratch กับ server เดียวกันและให้ตัวเลขตามที่แสดง (ไม่ถูกรันโดยตัวตรวจอัตโนมัติของคอร์ส)

คุณเรียก updateOne(filter, { name: "X" }) ด้วย document ธรรมดาที่ไม่มี operator ใน mongosh 2.11 หรือ Node driver 7.7 เกิดอะไรขึ้น?
หลังอัปเดต matchedCount เป็น 1 แต่ modifiedCount เป็น 0 เพราะอะไร?
operator ใดลบ field ออกจาก document ทั้งหมด?
จะต่อท้ายสมาชิกหนึ่งตัวใน field array โดยไม่แทนที่ทั้ง array ได้อย่างไร?
คุณ replaceOne({ name: "Grace" }, { name: "Grace H.", fines: 9 }) กับ document ที่เคยมี joined, city และ borrowed ด้วย เหลืออะไร?
findOneAndUpdate({ _id: "orders" }, { $inc: { n: 1 } }) โดยไม่มี option คืน document ไหน?