MongoDB findAndModify, findOneAndUpdate, findOneAndDelete & findOneAndReplace
Learn MongoDB's atomic find-and-modify style methods — findAndModify(), findOneAndUpdate(), findOneAndDelete(), and findOneAndReplace() — with returnNewDocument examples.
Find-and-Modify Methods
These methods find a document and change it in one atomic operation, optionally handing back either the pre- or post-update version of that document.
findAndModify()
Updates a single matching document and, by default, returns the document as it looked before the update.
db.employees.findAndModify({
query: { empid: 202 },
update: { $set: { age: 23 } }
})
// returns the OLD document — but the update did happen; re-run find() to confirm
Pass new: true to get the updated document back instead:
db.employees.findAndModify({
query: { empid: 202 },
update: { $set: { age: 24 } },
new: true
})
findOneAndUpdate()
The modern equivalent of findAndModify() for updates. Same default behavior — returns the pre-update document unless returnNewDocument: true is passed.
db.employees.findOneAndUpdate(
{ empid: 202 },
{ $inc: { salary: 5000 } },
{ returnNewDocument: true }
)
findOneAndDelete()
Finds and deletes the first matching document in one step, returning the document that was deleted (or null if nothing matched).
db.employees.findOneAndDelete({ empid: 212 })
// returns the deleted document
db.employees.findOneAndDelete({ empid: 213 })
// null — no document with that empid existed
findOneAndReplace()
Replaces an entire matching document with a new one — unlike $set, this doesn't merge fields, it swaps the whole document (keeping only _id).
db.employees.findOneAndReplace(
{ empid: 204 },
{ salary: 20000, email: "pritygupta@gmail.com", phone: 4444444444, empid: 204 },
{ returnNewDocument: true }
)
If your replacement document is missing a field with a unique index (like email), MongoDB may throw a duplicate-key error trying to write null for it — always include your unique fields in the replacement document.
Common Errors & Troubleshooting
- Confused why the "returned" document doesn't reflect your update — by default, all of these methods return the document as it was before the change; add
new: true(forfindAndModify) orreturnNewDocument: true(forfindOneAndUpdate) to see the post-update version. findOneAndReplace()unexpectedly wiping out fields — a replace swaps the entire document body (except_id); any field you don't include in the replacement document is gone. UsefindOneAndUpdate()with$setinstead if you only want to change specific fields.findOneAndDelete()returningnull— this just means no document matched the filter; it's not an error, just an empty result.
Key Takeaways
- All four methods combine "find" and "change" into a single atomic step — no separate find-then-update round trip.
- By default they return the document as it was before the change; use
new: true/returnNewDocument: trueto get the updated version. findOneAndReplace()swaps the whole document body, unlikefindOneAndUpdate()which merges via operators like$set.