Master MongoDB ACID transactions for multi-document operations. Learn session management, transaction mechanics, error handling, and production patterns. Guarantee data consistency across multiple operations.
Implement MongoDB ACID transactions for multi-document operations. Use when you need atomic updates across collections for money transfers, order processing, or inventory management.
/plugin marketplace add pluginagentmarketplace/custom-plugin-mongodb/plugin install mongodb-developer-plugin@pluginagentmarketplace-mongodbThis skill inherits all available tools. When active, it can use any tool Claude has access to.
assets/config.yamlreferences/GUIDE.mdscripts/helper.pyGuarantee consistency with ACID transactions across multiple operations.
const session = client.startSession()
try {
await session.withTransaction(async () => {
// All operations here are atomic
await users.insertOne({ name: 'John' }, { session })
await accounts.insertOne({ userId: 'xxx', balance: 100 }, { session })
// If any fails, ALL roll back
})
} catch (error) {
console.error('Transaction failed:', error)
} finally {
await session.endSession()
}
async function transferMoney(fromId, toId, amount) {
const session = client.startSession()
try {
await session.withTransaction(async () => {
// Deduct from account A
await accounts.updateOne(
{ _id: fromId },
{ $inc: { balance: -amount } },
{ session }
)
// Add to account B
await accounts.updateOne(
{ _id: toId },
{ $inc: { balance: amount } },
{ session }
)
// Both succeed, or both rollback - NO PARTIAL TRANSFERS!
})
} catch (error) {
// Transaction failed, money not transferred
console.error('Transfer failed:', error)
} finally {
await session.endSession()
}
}
const session = client.startSession()
// Configure session
const session = client.startSession({
defaultTransactionOptions: {
readConcern: { level: 'snapshot' },
writeConcern: { w: 'majority' },
readPreference: 'primary'
}
})
// 1. Start session
const session = client.startSession()
// 2. Start transaction
session.startTransaction()
// 3. Execute operations with session
await collection.insertOne(doc, { session })
// 4. Commit or abort
await session.commitTransaction() // Success
await session.abortTransaction() // Rollback
// 5. End session
await session.endSession()
// snapshot: See committed data at transaction start
// local: See latest data (default)
// majority: See data confirmed on majority
// linearizable: Latest confirmed data
await session.withTransaction(async () => {
// Operations
}, {
readConcern: { level: 'snapshot' }
})
// w: 1 (default): Acknowledged by primary
// w: 'majority': Acknowledged by majority
// w: N: Acknowledged by N replicas
await session.withTransaction(async () => {
// Operations
}, {
writeConcern: { w: 'majority' }
})
// primary: Read from primary only
// primaryPreferred: Primary, fallback to secondary
// secondary: Read from secondary
// secondaryPreferred: Secondary, fallback to primary
// nearest: Nearest server
{
readPreference: 'primary'
}
async function robustTransaction() {
const session = client.startSession()
try {
await session.withTransaction(async () => {
// Operations
})
} catch (error) {
if (error.hasErrorLabel('TransientTransactionError')) {
// Temporary error - retry
return robustTransaction()
} else if (error.hasErrorLabel('UnknownTransactionCommitResult')) {
// Commit outcome unknown - check state
console.log('Commit outcome unknown')
} else {
// Fatal error
throw error
}
} finally {
await session.endSession()
}
}
async function executeWithRetry(fn, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
const session = client.startSession()
try {
await session.withTransaction(async () => {
await fn(session)
})
return // Success
} catch (error) {
if (error.hasErrorLabel('TransientTransactionError') && attempt < maxRetries) {
continue // Retry
} else {
throw error
}
} finally {
await session.endSession()
}
}
}
async function placeOrder(userId, items) {
const session = client.startSession()
try {
await session.withTransaction(async () => {
// 1. Create order
const order = {
userId,
items,
status: 'pending',
createdAt: new Date()
}
const orderResult = await orders.insertOne(order, { session })
// 2. Update inventory
for (const item of items) {
const updated = await products.findOneAndUpdate(
{ _id: item.productId },
{ $inc: { stock: -item.quantity } },
{ session, returnDocument: 'after' }
)
// Check if stock went negative
if (updated.value.stock < 0) {
throw new Error('Insufficient inventory')
}
}
// 3. Deduct from user account
const userUpdate = await users.findOneAndUpdate(
{ _id: userId },
{ $inc: { balance: -calculateTotal(items) } },
{ session, returnDocument: 'after' }
)
if (userUpdate.value.balance < 0) {
throw new Error('Insufficient funds')
}
return orderResult.insertedId
})
} catch (error) {
// ALL operations rolled back if any fails
// Inventory stays same
// User balance unchanged
// Order not created
console.error('Order failed:', error.message)
throw error
} finally {
await session.endSession()
}
}
async function reconcileAccounts(mainId, secondaryIds) {
const session = client.startSession()
try {
await session.withTransaction(async () => {
// Calculate total balance
const secondary = await accounts.find(
{ _id: { $in: secondaryIds } },
{ session }
).toArray()
const totalBalance = secondary.reduce((sum, acc) => sum + acc.balance, 0)
// Update main account
await accounts.updateOne(
{ _id: mainId },
{ $set: { balance: totalBalance } },
{ session }
)
// Delete secondary accounts
await accounts.deleteMany(
{ _id: { $in: secondaryIds } },
{ session }
)
// Log reconciliation
await reconciliationLog.insertOne({
mainId,
secondaryIds,
totalBalance,
timestamp: new Date()
}, { session })
// All succeed together, or all rollback
})
} finally {
await session.endSession()
}
}
- Maximum 16MB of write operations
- Cannot create/drop collections
- Cannot create/drop indexes
- Cannot alter collections
- Cannot write to system collections
- Transactions have overhead
- Write operations slower (more coordination)
- Locking increases lock contention
- Not for every operation
✅ Transaction Best Practices:
✅ When to Use:
❌ When NOT to Use:
Guarantee consistency with transactions! ✅
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.