Atomicity & Transactions
Multi-document Transactions
Sessions, startTransaction, commit — and the transfer-between-accounts example done properly.
A transaction makes several reads and writes on a session commit as one or abort as one. You need a replica set (or mongos). Standalone mongod is the wrong demo for production semantics. Snapshot isolation: inside the transaction you see a consistent cut; outside, others see nothing until commit.
const session = client.startSession();
try {
session.startTransaction();
await db.collection("orders").insertOne(
{
userId: ObjectId("64a1b2c3d4e5f6a7b8c90001"),
items: [{ name: "Mechanical Keyboard", quantity: 1, unitPrice: 4500 }],
amount: 4500,
status: "pending",
},
{ session },
);
const stock = await db.collection("products").updateOne(
{ name: "Mechanical Keyboard", stock: { $gte: 1 } },
{ $inc: { stock: -1 } },
{ session },
);
if (stock.matchedCount === 0) {
throw new Error("sold out");
}
await session.commitTransaction();
} catch (err) {
await session.abortTransaction();
throw err;
} finally {
await session.endSession();
}The interview classic is the same shape with two accounts: $inc: { balance: -500 } on Rahul, $inc: { balance: 500 } on Priya, abort if Rahul's filter balance: { $gte: 500 } misses. In Node, `withTransaction` retries transient errors (failover, TransientTransactionError). Do not retry a sold-out matchedCount as if it were transient.
- Pass `{ session }` on every operation that belongs in the txn. Forget one write and it commits outside.
- Lifetime. Default ~60 seconds. Long reports do not belong here.
- Write concern. Majority is the sane commit; unacknowledged writes cannot be transactional.
- Creates. Avoid
createIndex/createCollectioninside a txn. Have the collections first.
Interview question
How do you run a multi-document transaction in MongoDB?
Start a session, startTransaction, pass the session into every read and write, commit or abort. Replica set required. Typical example: debit one document and credit another, or insert an order and $inc stock. Retry transient transaction errors; do not retry a filter that correctly matched nothing. Keep it short — default max is about a minute.