replaceOne
replaceOne vs updateOne in MongoDB. When each is right, and the surprises that bite when you mix them up.
MongoDB — replaceOne
EXAMPLE
// ===== updateOne =====
// Modifies SPECIFIC fields using update operators.
db.users.updateOne(
{ _id: ObjectId('...') },
{ $set: { name: 'Alex Chen' }, $inc: { logins: 1 } }
);
// Other fields are UNCHANGED.
// ===== replaceOne =====
// Replaces the WHOLE document (except _id).
db.users.replaceOne(
{ _id: ObjectId('...') },
{ name: 'Alex Chen', email: 'alex@example.com', logins: 1 }
);
// Any fields not in the replacement document are GONE.
// ===== When to use replaceOne =====
// - Rewriting an entire entity (whole DTO from the API)
// - Bulk migrations where shape changes
// - You explicitly want to drop deprecated fields
// ===== When to use updateOne =====
// - Modifying one or a few fields
// - Atomic operators ($inc, $push, $pull, $addToSet, $set, $unset)
// - Partial updates from PATCH-style APIs
// ===== Filter + immutable _id =====
// The filter must match exactly ONE document for *One variants.
// _id cannot be changed by replaceOne (it errors if you try).
db.users.replaceOne(
{ _id: oldId },
{ _id: newId, ... } // throws
);
// ===== Upsert =====
db.users.replaceOne(
{ email: 'alex@example.com' },
{ email: 'alex@example.com', name: 'Alex' },
{ upsert: true }
);
// If no doc matches the filter, the replacement is INSERTED.
// ===== Common driver examples =====
// Node:
import { MongoClient } from 'mongodb';
const client = new MongoClient(uri); await client.connect();
const users = client.db('shop').collection('users');
await users.replaceOne(
{ _id: id },
{ name: 'Alex', email: 'a@x.io' },
);
await users.updateOne(
{ _id: id },
{ $set: { lastLogin: new Date() } },
);
// Python:
from pymongo import MongoClient
c = MongoClient(uri)
users = c.shop.users
users.replace_one({'_id': id}, {'name': 'Alex'})
users.update_one({'_id': id}, {'$set': {'lastLogin': datetime.utcnow()}})
// ===== Mass replace =====
// There is no replaceMany. For bulk operations, use:
// bulkWrite + replaceOne entries, OR
// updateMany + $set / $unset for partial rewrites
// ===== Patterns to internalise =====
// - updateOne for surgical changes; replaceOne for whole-doc rewrites
// - findOneAndUpdate / findOneAndReplace for read-after-write
// - Upsert when you want INSERT-or-UPDATE in one round trip
// - bulkWrite for batches
// ===== Pitfalls =====
// - replaceOne with a missing field -> the existing field is GONE
// - Forgetting that 'updateOne' without operators is a syntax error
// - Trying to change _id with replaceOne -> exception
// - Race conditions on read-then-write; prefer atomic update operators
Why it matters
updateOne for partial changes; replaceOne for whole-doc rewrites. Mix them up and you silently drop fields. When the API speaks PATCH, use updateOne with $set; when it speaks PUT, use replaceOne. Upsert is the third option that combines insert and update in one round trip.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…