Updating in place with operators is atomic and avoids read-modify-write races.
updateOne(filter, update, options) changes the first matching document; updateMany changes all matches. The update uses update operators:
$set: { status: "shipped" }sets fields (creating them, including nested paths),$unset: { coupon: "" }removes them,$inc: { stock: -1 }adds to a number,$min/$maxkeep the smaller/larger value,$push: { tags: "sale" }appends to an array,$addToSetappends only if absent,$pullremoves matching elements,$currentDate: { updatedAt: true }stamps the server time.
The result reports matchedCount and modifiedCount; setting a field to the value it already has counts as matched but not modified.
With { upsert: true }, if nothing matches, a new document is built from the equality fields of the filter plus the update, which is handy for counters and "create or update" endpoints.
Each update to one document is atomic, so $inc from many clients at once never loses an increment, unlike reading a value, adding in your code and writing it back.
To swap the whole document use replaceOne(filter, newDoc). Passing a plain document without operators to updateOne is an error, which protects you from accidentally wiping fields. findOneAndUpdate returns the document before or after the change (returnDocument: "after").
Example
db.stock.insertOne({ _id: "PEN-01", qty: 10, tags: ["office"] })
db.stock.updateOne(
{ _id: "PEN-01" },
{ $inc: { qty: -3 }, $addToSet: { tags: "sale" }, $currentDate: { updatedAt: true } }
)
// { acknowledged: true, matchedCount: 1, modifiedCount: 1, upsertedCount: 0, ... }
db.stock.findOne({ _id: "PEN-01" }, { qty: 1, tags: 1 })
// { _id: 'PEN-01', qty: 7, tags: [ 'office', 'sale' ] }
db.pageviews.updateOne({ page: "/home" }, { $inc: { views: 1 } }, { upsert: true })
// first call: upsertedCount: 1 and creates { page: '/home', views: 1 }
db.stock.updateOne({ _id: "PEN-01" }, { qty: 0 })
// MongoInvalidArgumentError: Update document requires atomic operatorsRemember
- Use operators: $set/$unset, $inc, $push/$addToSet/$pull
- updateOne changes the first match, updateMany all matches
- upsert: true inserts when nothing matches
- Operator updates are atomic per document: no lost increments
Watch out for
- Reading a value, changing it in application code and writing it back: concurrent requests overwrite each other; use $inc or $set with a condition.