For many years, the biggest argument against using MongoDB (or any NoSQL database) for critical financial applications was a lack of “ACID Transactions.” Critics argued that if you were building a banking app, you had to use a relational SQL database.
That argument is no longer valid. Starting in version 4.0, MongoDB introduced Multi-Document ACID Transactions, giving developers the flexibility of a document model with the rock-solid data integrity guarantees of a traditional relational database.
In this module, we will explore what transactions are, what ACID means, and how to use them.
What is a Transaction?
Imagine you are building a banking application. A user wants to transfer $100 from Account A to Account B.
In the database, this requires two separate operations:
- Deduct $100 from Account A.
- Add $100 to Account B.
But what happens if the server crashes exactly after step 1, but before step 2? Account A has lost $100, but Account B never received it. That $100 has completely vanished into the digital void. This is a catastrophic failure for a bank.
A Transaction solves this. A transaction is a wrapper around multiple database operations that guarantees they are treated as a single, indivisible unit of work.
It is “All or Nothing.” If a transaction is initiated, either both Step 1 and Step 2 succeed, or if anything goes wrong, the database instantly rolls back Step 1 as if it never happened. The $100 is safely returned to Account A.
The ACID Properties
For a database to support true transactions, it must guarantee four properties, known by the acronym ACID:
- (A)tomicity: The “All or Nothing” rule. All operations in the transaction succeed, or they all fail. There are no partial updates.
- (C)onsistency: The transaction must take the database from one valid state to another valid state, obeying all rules and constraints (e.g., account balances cannot go below zero).
- (I)solation: If two people try to transfer money at the exact same millisecond, their transactions will not interfere with each other. The database processes them in a way that makes it look like they occurred sequentially.
- (D)urability: Once a transaction is successfully completed (committed), the changes are permanently saved to the hard drive. Even if the server loses power a microsecond later, the data is safe.
(Note: MongoDB has always supported ACID properties at the Single-Document level. If you update a document with an embedded array, the entire document is updated atomically. Multi-Document Transactions simply extend this guarantee across multiple separate documents or collections).
When to Use Multi-Document Transactions
Transactions are computationally expensive. They require the database to place “locks” on data, which can slow down other operations.
You should NOT use transactions for everything.
Because MongoDB is a document database, you should first try to model your data so that related information is embedded in a single document (which, as mentioned, is automatically ACID compliant).
You SHOULD use transactions when:
- You are updating documents in multiple different collections that must remain perfectly synchronized (e.g., deducting inventory in the
productscollection while creating an invoice in theorderscollection). - You are dealing with highly sensitive financial or medical data where partial updates are completely unacceptable.
Transaction Example (Using Node.js)
Transactions in MongoDB require a concept called a Session. You start a session, tell the session to start a transaction, pass that session to all your database operations, and then finally tell the session to commit or abort.
Note: You generally run transactions in your application backend (like Node.js, Python, or Java) rather than directly in the MongoDB shell.
Here is what a banking transaction looks like in Node.js using the official MongoDB driver:
// 1. Start a Client Session
const session = client.startSession();
try {
// 2. Start the Transaction
session.startTransaction();
// 3. Perform Operations (You MUST pass the 'session' object to each operation!)
// Deduct $100 from Account A
await accountsCollection.updateOne(
{ accountName: "Account A" },
{ $inc: { balance: -100 } },
{ session } // Passing the session links this operation to the transaction
);
// Add $100 to Account B
await accountsCollection.updateOne(
{ accountName: "Account B" },
{ $inc: { balance: 100 } },
{ session }
);
// 4. Commit the Transaction (Saves the data permanently)
await session.commitTransaction();
console.log("Transaction completely successful!");
} catch (error) {
// 5. Abort the Transaction (Rollback on error)
console.log("An error occurred. Rolling back all changes...");
await session.abortTransaction();
} finally {
// 6. End the session
session.endSession();
}
If the server crashes on the second updateOne, the catch block is triggered, abortTransaction() is called, and the $100 is instantly returned to Account A.
Important Requirements for Transactions
To use Multi-Document Transactions in MongoDB, your database environment must meet specific requirements:
- Replica Sets or Sharded Clusters Only: You cannot run transactions on a standalone MongoDB server. The server must be configured as a Replica Set (which Atlas does for you automatically).
- WiredTiger Storage Engine: Transactions rely on the WiredTiger storage engine (which has been the default since MongoDB 3.2).
- Execution Time Limit: By default, a transaction must complete within 60 seconds. If it takes longer, MongoDB will automatically abort it to prevent the database from locking up indefinitely.
Summary
With the introduction of Multi-Document ACID Transactions, MongoDB eliminated the last major barrier for enterprise adoption.
- A Transaction groups multiple database operations into a single “All or Nothing” unit of work.
- ACID stands for Atomicity, Consistency, Isolation, and Durability.
- You execute transactions by tying your operations to a Session.
- Remember: Because of the performance cost, always try to design your schema to avoid multi-document updates via Embedding before resorting to Transactions!
In Module 18, we will take a closer look at the architecture that makes all of this high-availability possible: Replication!
Discussion
Loading comments...