How to Use Transactions in Mongoose for MongoDB
To use
transactions in Mongoose, start a session with startSession(), then execute your operations inside session.withTransaction(). This ensures all operations succeed or fail together, keeping your data consistent.Syntax
Using transactions in Mongoose involves these steps:
- Start a session: Call
startSession()on your Mongoose connection. - Run transaction: Use
session.withTransaction()to run your operations atomically. - Commit or abort: The transaction commits if all operations succeed, otherwise it aborts.
javascript
const session = await mongoose.startSession(); await session.withTransaction(async () => { // Your database operations here await Model.create([{ name: 'Example' }], { session }); // More operations }); session.endSession();
Example
This example shows how to transfer money between two user accounts atomically using a transaction. Both debit and credit operations succeed or fail together.
javascript
const mongoose = require('mongoose'); async function runTransaction() { const session = await mongoose.startSession(); try { await session.withTransaction(async () => { const User = mongoose.model('User', new mongoose.Schema({ name: String, balance: Number })); const sender = await User.findOne({ name: 'Alice' }).session(session); const receiver = await User.findOne({ name: 'Bob' }).session(session); if (sender.balance < 100) { throw new Error('Insufficient funds'); } sender.balance -= 100; receiver.balance += 100; await sender.save({ session }); await receiver.save({ session }); }); console.log('Transaction committed successfully'); } catch (error) { console.log('Transaction aborted:', error.message); } finally { session.endSession(); } } runTransaction();
Output
Transaction committed successfully
Common Pitfalls
Common mistakes when using transactions in Mongoose include:
- Not passing the
sessionoption to all operations inside the transaction, causing them to run outside the transaction. - Forgetting to
endSession(), which can lead to resource leaks. - Running transactions on standalone MongoDB servers; transactions require a replica set or sharded cluster.
- Not handling errors properly inside
withTransaction, which can cause unexpected behavior.
javascript
/* Wrong: Missing session option */ await User.create({ name: 'Charlie' }); // This runs outside transaction /* Right: Pass session to all operations */ await User.create([{ name: 'Charlie' }], { session });
Quick Reference
| Step | Description |
|---|---|
| startSession() | Begin a new session for the transaction |
| withTransaction(fn) | Run your operations inside this function atomically |
| Pass { session } | Include session option in all DB operations inside transaction |
| endSession() | Close the session after transaction completes |
Key Takeaways
Always start a session with mongoose.startSession() before running a transaction.
Use session.withTransaction() to run multiple operations atomically.
Pass the session option to every database operation inside the transaction.
Transactions require MongoDB replica sets or sharded clusters to work.
Always end the session with session.endSession() to free resources.