Advanced MongoDB

Multi-Document Transactions in MongoDB

Implement ACID transactions across multiple documents and collections with session management.

8 min read Tutorial

Transactions in MongoDB

Starting with version 4.0, MongoDB supports multi-document ACID transactions. This means you can read and write to multiple documents across multiple collections atomically -- either all operations succeed or none of them are applied. Transactions are essential for operations like transferring funds between accounts, where partial updates would leave data in an inconsistent state.

Basic Transaction Flow

Transactions require a session. You start the session, begin a transaction, perform operations, then commit or abort:

const session = db.getMongo().startSession()
session.startTransaction()

try {
  const accounts = session.getDatabase("bank").accounts

  // Debit from source account
  accounts.updateOne(
    { _id: "account-A" },
    { $inc: { balance: -100 } },
    { session }
  )

  // Credit to destination account
  accounts.updateOne(
    { _id: "account-B" },
    { $inc: { balance: 100 } },
    { session }
  )

  // All operations succeeded -- commit
  session.commitTransaction()
} catch (error) {
  // Something went wrong -- abort all changes
  session.abortTransaction()
  throw error
} finally {
  session.endSession()
}

Cross-Collection Transactions

Transactions can span multiple collections, which is useful for maintaining referential integrity:

const session = db.getMongo().startSession()
session.startTransaction()

try {
  const db = session.getDatabase("ecommerce")

  // Create the order
  db.orders.insertOne({
    customerId: "cust-123",
    items: [{ productId: "prod-A", qty: 2, price: 29.99 }],
    total: 59.98,
    status: "confirmed",
    createdAt: new Date()
  }, { session })

  // Decrement inventory
  db.products.updateOne(
    { _id: "prod-A", stock: { $gte: 2 } },
    { $inc: { stock: -2 } },
    { session }
  )

  // Record payment
  db.payments.insertOne({
    customerId: "cust-123",
    amount: 59.98,
    method: "credit_card",
    processedAt: new Date()
  }, { session })

  session.commitTransaction()
} catch (error) {
  session.abortTransaction()
  throw error
} finally {
  session.endSession()
}

Transaction Options

You can configure read concern, write concern, and read preference for transactions:

session.startTransaction({
  readConcern: { level: "snapshot" },
  writeConcern: { w: "majority" },
  readPreference: "primary",
  maxCommitTimeMS: 5000
})

The "snapshot" read concern ensures consistent reads within the transaction. The "majority" write concern ensures durability.

Retry Logic

Transient transaction errors (such as write conflicts) can be retried. MongoDB drivers provide built-in retry helpers:

async function runTransactionWithRetry(session, txnFunc) {
  while (true) {
    try {
      await txnFunc(session)
      break
    } catch (error) {
      if (error.hasErrorLabel("TransientTransactionError")) {
        console.log("Transient error, retrying transaction...")
        continue
      }
      throw error
    }
  }
}

async function commitWithRetry(session) {
  while (true) {
    try {
      await session.commitTransaction()
      break
    } catch (error) {
      if (error.hasErrorLabel("UnknownTransactionCommitResult")) {
        console.log("Retrying commit...")
        continue
      }
      throw error
    }
  }
}

When to Use Transactions

Transactions add overhead, so use them only when necessary:

  • Use transactions for: Financial operations, inventory management, multi-collection updates requiring atomicity.
  • Avoid transactions when: A single document update suffices, or when you can design your schema to keep related data in one document.

Well-designed schemas that embed related data often eliminate the need for multi-document transactions altogether.

Key Takeaways

  • Transactions provide ACID guarantees across multiple documents and collections.
  • Always use a session and wrap operations in try/catch with abort on failure.
  • Implement retry logic for transient errors and unknown commit results.
  • Prefer schema design that minimizes the need for transactions.

Try this query in UnifySQL

Write, optimize, and collaborate on MongoDB queries with AI assistance.

Start Free