This chapter provides a detailed guide on implementing multi-document transactions in MongoDB, including fundamental concepts, usage scenarios, and advanced transaction handling techniques. Multi-document transactions allow developers to ensure data consistency across multiple documents and collections in complex database operations.
A transaction is a sequence of database operations that are executed as a single unit of work. Multi-document transactions ensure that all operations within the transaction succeed or fail together, achieving ACID compliance (Atomicity, Consistency, Isolation, Durability).
Transactions begin with a session, a mechanism to maintain the state of operations across multiple documents or collections.
const session = client.startSession();
try {
session.startTransaction();
// Database operations go here
session.commitTransaction();
} catch (error) {
session.abortTransaction();
console.error("Transaction aborted due to error:", error);
} finally {
session.endSession();
}
startTransaction()
: Initializes a transaction.commitTransaction()
: Commits the transaction, making all changes permanent.abortTransaction()
: Aborts the transaction, discarding any changes.MongoDB uses snapshot isolation, meaning each transaction sees a consistent snapshot of the data as it was at the start of the transaction.
In this example, we perform a transfer between two accounts by updating both documents in a single transaction.
const session = client.startSession();
try {
session.startTransaction();
const accounts = db.collection("accounts");
// Withdraw from account A
await accounts.updateOne({ accountId: "A" }, { $inc: { balance: -100 } }, { session });
// Deposit to account B
await accounts.updateOne({ accountId: "B" }, { $inc: { balance: 100 } }, { session });
// Commit the transaction
await session.commitTransaction();
console.log("Transfer completed successfully");
} catch (error) {
await session.abortTransaction();
console.error("Transaction aborted due to error:", error);
} finally {
session.endSession();
}
Transactions are not limited to a single collection. Multiple collections can be updated within the same transaction, useful in complex applications.
const session = client.startSession();
try {
session.startTransaction();
const users = db.collection("users");
const orders = db.collection("orders");
// Insert a new order
await orders.insertOne({ orderId: "123", total: 200 }, { session });
// Update user balance
await users.updateOne({ userId: "u1" }, { $inc: { balance: -200 } }, { session });
await session.commitTransaction();
console.log("Order created and user balance updated");
} catch (error) {
await session.abortTransaction();
console.error("Transaction aborted:", error);
} finally {
session.endSession();
}
retryWrites
set to true
in the MongoDB driver.Transactions begin with a session, a mechanism to maintain the state of operations across multiple documents or collections.
const session = client.startSession();
try {
session.startTransaction();
// Database operations go here
session.commitTransaction();
} catch (error) {
session.abortTransaction();
console.error("Transaction aborted due to error:", error);
} finally {
session.endSession();
}
async
function to implement retry logic.
async function runTransactionWithRetry(session, transactionFunction) {
while (true) {
try {
await transactionFunction(session);
break;
} catch (error) {
if (error.hasErrorLabel("TransientTransactionError")) {
console.log("TransientTransactionError, retrying transaction...");
} else {
throw error;
}
}
}
}
MongoDB’s profiler can be used to monitor transaction performance, logging detailed information about operations.
session.startTransaction({ maxCommitTimeMS: 120000 });
Multi-document transactions in MongoDB allow for robust data consistency across collections and documents. By understanding the mechanisms of session, transaction isolation, and error handling, developers can create applications that handle complex, multi-step operations reliably. Following best practices and using transactions strategically ensures MongoDB’s performance remains optimal. Happy coding !❤️