The first time I tried to “rollback” data in MongoDB, I thought it would work like SQL.
Something fails → database magically goes back to the previous state. Simple, right?
Wrong.
I had already updated two collections.
The third operation failed.
Now my data was half-updated and half-broken.
That was the day I learned how MongoDB really handles transactions and rollbacks.
If you’re coming from MySQL or PostgreSQL, MongoDB transactions can feel confusing at first.
This post is for that exact confusion.
What rollback means in MongoDB (in plain words)
In simple terms, rollback means undoing changes if something fails.
In MongoDB, rollback only works inside a transaction.
Outside a transaction, MongoDB will not undo anything automatically.
So this is important:
MongoDB does NOT support rollback for normal single operations.
Rollback happens only when:
- You start a transaction
- Something fails
- You abort the transaction
If you don’t use transactions, rollback is your responsibility.
When do you actually need transactions?
MongoDB is document-based.
Many times, one document update is enough.
But transactions matter when:
- You update multiple documents
- Or update multiple collections
- And all changes must succeed together
Real-life example:
You are building a payment system.
Steps:
- Deduct money from user wallet
- Create an order
- Update product stock
If step 2 fails, step 1 must be undone.
That’s where transaction rollback comes in.
Important requirement most beginners miss
Before jumping into code, one hard truth:
MongoDB transactions only work on replica sets or sharded clusters
They do NOT work on standalone MongoDB.
Even on localhost, you must run MongoDB as a replica set.
Many “transaction not working” issues come from this mistake.
Basic transaction flow in MongoDB
The transaction flow is always the same:
- Start a session
- Start a transaction
- Do database operations
- Commit if everything is OK
- Abort if something fails (rollback)
Think of it like writing on a whiteboard:
- Commit = make it permanent
- Abort = erase everything you wrote
Simple rollback example (Node.js)
Let’s use a simple example.
We will:
- Deduct balance from a user
- Create an order
- Rollback if anything fails
const session = await mongoose.startSession();
try {
session.startTransaction();
await User.updateOne(
{ _id: userId },
{ $inc: { balance: -500 } },
{ session }
);
await Order.create(
[{ userId, amount: 500 }],
{ session }
);
await session.commitTransaction();
session.endSession();
console.log("Transaction successful");
} catch (error) {
await session.abortTransaction();
session.endSession();
console.log("Transaction rolled back");
}
If any line inside try fails, MongoDB rolls back everything.
Balance deduction? Undone.
Order creation? Gone.
That’s rollback.
What actually happens during rollback?
MongoDB does not “reverse” each query.
Instead:
- It keeps all changes isolated inside the transaction
- Nothing is written permanently until
commitTransaction() -
abortTransaction()simply throws everything away
So rollback is fast and safe.
This also means:
- Other users cannot see half-done data
- Either everything happens or nothing happens
Single document updates don’t need rollback
This is a common misunderstanding.
MongoDB guarantees atomicity at document level.
Example:
db.users.updateOne(
{ _id: 1 },
{ $inc: { balance: -100 } }
)
This update is already atomic.
It will either fully succeed or fully fail.
No transaction needed.
No rollback needed.
Use transactions only when multiple operations are involved.
Common mistakes and myths
Myth 1: MongoDB auto-rollbacks failed queries
False.
If you run multiple updates without a transaction, MongoDB will not rollback anything.
Myth 2: Transactions make MongoDB slow always
Not true.
They add overhead, yes.
But used correctly, they are fine for critical operations.
Just don’t wrap every query in a transaction.
Mistake 1: Forgetting to pass session
This is very common.
await User.updateOne({ _id }, { name: "A" }); // ❌ no session
That query is outside the transaction.
Rollback will NOT affect it.
Every query inside a transaction must include { session }.
Mistake 2: Using transactions on standalone MongoDB
If your MongoDB is not a replica set, rollback simply won’t work.
Always check your setup first.
Rollback vs manual compensation
Sometimes transactions are not possible.
Example:
- You are calling a payment API
- You update MongoDB after payment success
You cannot rollback an external API call.
In those cases, you use manual compensation.
Example logic:
- If order creation fails
- Call refund API
- Update database again
Transactions are great, but they don’t solve everything.
Practical tips from real projects
Tip 1: Keep transactions short
Don’t do heavy logic inside a transaction.
Read, write, commit, exit.
Tip 2: Handle retries
MongoDB may throw transient errors.
Retry the whole transaction if needed.
Tip 3: Log aborted transactions
Rollback is not a failure.
But repeated rollbacks indicate a design issue.
Tip 4: Don’t fear rollback
Rollback is a safety net.
Design assuming things will fail.
A mental model that helps
Think of a MongoDB transaction like a Git branch.
- You make changes
- Nothing affects main branch
- Commit merges changes
- Abort deletes the branch
Once I started thinking this way, transactions became simple.
When NOT to use transactions
Avoid transactions when:
- You update only one document
- You can tolerate small inconsistencies
- Performance is extremely critical
MongoDB is flexible.
Not every problem needs rollback.
Final honest advice
MongoDB transactions are powerful, but they are not magic.
Rollback works only when:
- You explicitly use transactions
- Your setup supports it
- You pass the session correctly
If you are a beginner:
- First understand document-level atomicity
- Then move to transactions
Use rollback as a tool, not a habit.
Once you respect its limits, MongoDB becomes a very reliable database.
And yes, I still forget to pass { session } sometimes.
It happens to all of us.
Top comments (0)