What Is an Upsert in MongoDB?
Learn what an upsert is in MongoDB, how upsert true combines update and insert atomically, and how $setOnInsert helps with idempotent writes.
Expected Interview Answer
An upsert is a MongoDB write operation that updates a document matching a filter if one exists, or inserts a brand-new document based on that filter and update if none does, combining update and insert into a single atomic call.
You enable an upsert by passing { upsert: true } as an option to updateOne, updateMany, replaceOne, or findOneAndUpdate. If a document matching the query filter is found, MongoDB updates it normally. If no document matches, MongoDB constructs a new document using the filter's equality conditions plus whatever the update document specifies, and inserts it. This is atomic at the single-document level, so upserts avoid the classic race condition where you check-then-insert and another process beats you to it, which is why upserts are the standard pattern for idempotent writes like counters, caches, and deduplicated inserts. Using $setOnInsert lets you supply fields that should only be set when a new document is actually created, not on updates.
- Avoids separate read-then-write race conditions with a single atomic call
- Simplifies idempotent writes for counters, caches, and unique records
- $setOnInsert lets you set creation-only fields cleanly
- Works across updateOne, updateMany, replaceOne, and findOneAndUpdate
- Reduces round trips compared to a manual find-then-insert-or-update flow
AI Mentor Explanation
An upsert is like a scorer who checks the wagon-wheel chart for a batter's name: if the entry already exists, they add the new shot to it, and if it doesn't, they create a fresh entry for that batter on the spot rather than leaving the shot unrecorded. One motion at the scoring table either extends existing data or starts it, with no separate step required to first check and then decide.
Step-by-Step Explanation
Step 1
Set upsert: true
Pass { upsert: true } as an option to updateOne, updateMany, replaceOne, or findOneAndUpdate.
Step 2
Match attempt
MongoDB first tries to find a document matching the filter; if found, the update is applied normally.
Step 3
No match, insert
If nothing matches, MongoDB creates a new document from the filter's equality fields plus the update document's changes.
Step 4
$setOnInsert for creation-only fields
Use $setOnInsert inside the update to specify fields that should only be applied when a new document is actually inserted.
Step 5
Atomicity guarantee
The find-or-insert decision happens atomically at the document level, eliminating the race condition of a manual check-then-write.
What Interviewer Expects
- Explains that upsert combines update-if-exists and insert-if-not into one atomic call
- Knows which methods accept the upsert option
- Can describe $setOnInsert and why it matters
- Understands the race-condition problem upsert solves
- Can give a real use case like counters or idempotent writes
Common Mistakes
- Thinking upsert always inserts a duplicate even if a match exists
- Forgetting that fields from the filter get copied into the newly inserted document
- Using $set for a field that should only be set on insert instead of $setOnInsert
- Assuming upsert is available on find() reads instead of write operations
Best Answer (HR Friendly)
“An upsert is a shortcut that either updates existing data or creates it if it doesn't exist yet, all in one safe step. It's commonly used for things like tracking counts or saving user preferences, so the application doesn't need extra logic to check whether a record already exists before saving.”
Code Example
// Increment a page view counter, creating it if it doesn't exist
db.pageViews.updateOne(
{ page: '/pricing' },
{
$inc: { views: 1 },
$setOnInsert: { createdAt: new Date() }
},
{ upsert: true }
);
// First call: creates { page: '/pricing', views: 1, createdAt: ... }
// Every call after: increments views, createdAt stays untouchedFollow-up Questions
- What happens to fields from the filter when an upsert inserts a new document?
- How does $setOnInsert differ from $set in an upsert?
- What race condition does an upsert prevent compared to find-then-insert logic?
- Can updateMany with upsert insert more than one document?
- How would you design a unique index to make an upsert-based counter safe under concurrency?
MCQ Practice
1. What does the upsert option do when no document matches the filter?
When upsert is true and no document matches, MongoDB creates a new document combining the filter's equality fields with the update.
2. Which operator ensures a field is only set when an upsert actually inserts a new document?
$setOnInsert applies its fields only during the insert branch of an upsert, never during a matched update.
3. Why is an upsert preferred over a manual find-then-insert-or-update sequence?
An upsert performs the check-and-write atomically at the document level, eliminating the race window a separate find-then-write pattern would have.
Flash Cards
What is an upsert? — A write operation that updates a matching document or inserts a new one if no match exists, atomically.
How do you enable upsert behavior? — Pass { upsert: true } as an option to updateOne, updateMany, replaceOne, or findOneAndUpdate.
What does $setOnInsert do in an upsert? — Sets fields only when the upsert actually inserts a new document, not when it updates an existing one.
What problem does upsert solve compared to manual find-then-write logic? — It eliminates the race condition where another process could insert between your check and your write.