Introduction to Transactions in MongoDB
Transactions in MongoDB allow multiple operations to be executed as a single atomic unit. Either all
operations within a transaction succeed, or none of them take effect. This ensures data consistency
and integrity, especially in scenarios involving multiple collections or documents.
Key Concepts
1. ACID Properties
• Atomicity: All operations in a transaction succeed or none do.
• Consistency: Data remains in a valid state before and after the transaction.
• Isolation: Transactions do not interfere with each other.
• Durability: Committed data is permanently saved, even in case of a failure.
2. Multi-Document Transactions MongoDB supports multi-document transactions for replica sets
and sharded clusters, allowing operations across multiple collections or databases.
3. Transaction Management Transactions begin with [Link]() and are committed
with [Link](). They can also be aborted using [Link]().
Practical Implementation
Prerequisites
1. Use replica sets or sharded clusters (transactions are not supported on standalone
MongoDB instances).
2. Use the MongoDB [Link] Driver, Mongo Shell, or any supported MongoDB client.
Example 1: Bank Transfer
Scenario: Transfer money between two accounts, ensuring both debit and credit operations are
atomic.
Steps:
• Debit amount from one account.
• Credit the same amount to another account.
Implementation:
javascript
Copy code
const session = await [Link]();
try {
[Link]();
await [Link]('accounts').updateOne(
{ accountId: 1 },
{ $inc: { balance: -100 } },
{ session }
);
await [Link]('accounts').updateOne(
{ accountId: 2 },
{ $inc: { balance: 100 } },
{ session }
);
await [Link]();
[Link]("Transaction committed.");
} catch (error) {
await [Link]();
[Link]("Transaction aborted: ", error);
} finally {
[Link]();
Example 2: E-commerce Order Processing
Scenario: Place an order:
• Decrement product stock.
• Create an order record.
• Update customer purchase history.
Implementation:
javascript
Copy code
const session = await [Link]();
try {
[Link]();
await [Link]('products').updateOne(
{ productId: "12345", stock: { $gte: 1 } },
{ $inc: { stock: -1 } },
{ session }
);
await [Link]('orders').insertOne(
{ orderId: "order123", productId: "12345", customerId: "cust001", date: new Date() },
{ session }
);
await [Link]('customers').updateOne(
{ customerId: "cust001" },
{ $push: { orderHistory: "order123" } },
{ session }
);
await [Link]();
[Link]("Order placed successfully.");
} catch (error) {
await [Link]();
[Link]("Order placement failed: ", error);
} finally {
[Link]();
}
Example 3: Student Enrollment System
Scenario: Enroll a student in a course:
• Add the student to the course roster.
• Deduct available slots in the course.
• Update student enrollment record.
Implementation:
javascript
Copy code
const session = await [Link]();
try {
[Link]();
await [Link]('courses').updateOne(
{ courseId: "cs101", availableSlots: { $gte: 1 } },
{ $inc: { availableSlots: -1 }, $push: { students: "student001" } },
{ session }
);
await [Link]('students').updateOne(
{ studentId: "student001" },
{ $push: { enrolledCourses: "cs101" } },
{ session }
);
await [Link]();
[Link]("Enrollment successful.");
} catch (error) {
await [Link]();
[Link]("Enrollment failed: ", error);
} finally {
[Link]();
Example 4: Healthcare Appointment Booking
Scenario: Book an appointment:
• Reserve a time slot for a patient.
• Update the doctor's schedule.
• Record the appointment in patient records.
Implementation:
javascript
Copy code
const session = await [Link]();
try {
[Link]();
await [Link]('doctors').updateOne(
{ doctorId: "doc123", "[Link]": "10:00AM", "[Link]": true },
{ $set: { "schedule.$.isAvailable": false } },
{ session }
);
await [Link]('appointments').insertOne(
{ appointmentId: "appt001", doctorId: "doc123", patientId: "pat001", time: "10:00AM" },
{ session }
);
await [Link]('patients').updateOne(
{ patientId: "pat001" },
{ $push: { appointments: "appt001" } },
{ session }
);
await [Link]();
[Link]("Appointment booked successfully.");
} catch (error) {
await [Link]();
[Link]("Booking failed: ", error);
} finally {
[Link]();
Example 5: Inventory and Supply Chain
Scenario: Restock inventory:
• Update supplier records.
• Update warehouse inventory.
• Log the restocking operation.
Implementation:
javascript
Copy code
const session = await [Link]();
try {
[Link]();
await [Link]('suppliers').updateOne(
{ supplierId: "sup001" },
{ $inc: { itemsSupplied: 50 } },
{ session }
);
await [Link]('inventory').updateOne(
{ productId: "prod001" },
{ $inc: { stock: 50 } },
{ session }
);
await [Link]('logs').insertOne(
{ action: "restock", productId: "prod001", quantity: 50, date: new Date() },
{ session }
);
await [Link]();
[Link]("Inventory restocked.");
} catch (error) {
await [Link]();
[Link]("Restocking failed: ", error);
} finally {
[Link]();
Real-World Benefits of Transactions
1. Banking: Ensure atomic money transfers to prevent data mismatches.
2. E-commerce: Prevent overselling by maintaining product stock accurately.
3. Education: Guarantee consistent enrollment data for students and courses.
4. Healthcare: Prevent double bookings by managing time slots atomically.
5. Supply Chain: Maintain inventory accuracy by logging all restocking operations.
By implementing transactions, MongoDB enables robust, consistent, and reliable applications
suitable for real-world complex scenarios.
You said:
kindly provide the proper step for example 1: bank transfer to implemented using mongosh shell
ChatGPT said:
ChatGPT
To implement Example 1: Bank Transfer using the MongoDB shell (mongosh), follow these steps:
Setup: Sample Database and Collections
1. Create the accounts collection:
javascript
Copy code
[Link]([
{ accountId: 1, name: "Alice", balance: 1000 },
{ accountId: 2, name: "Bob", balance: 500 }
]);
Initial State:
javascript
Copy code
[Link]().pretty();
Output:
json
Copy code
{ "_id": ObjectId("..."), "accountId": 1, "name": "Alice", "balance": 1000 },
{ "_id": ObjectId("..."), "accountId": 2, "name": "Bob", "balance": 500 }
Step-by-Step Implementation: Bank Transfer
Step 1: Start a Session
Start a new session:
javascript
Copy code
const session = [Link]().startSession();
Step 2: Start a Transaction
Start a transaction within the session:
javascript
Copy code
[Link]();
Step 3: Perform Debit Operation
Debit $100 from Alice's account:
javascript
Copy code
const aliceResult = [Link]("test").[Link](
{ accountId: 1, balance: { $gte: 100 } },
{ $inc: { balance: -100 } },
{ session }
);
if (![Link]) {
throw new Error("Insufficient funds in Alice's account.");
Step 4: Perform Credit Operation
Credit $100 to Bob's account:
javascript
Copy code
const bobResult = [Link]("test").[Link](
{ accountId: 2 },
{ $inc: { balance: 100 } },
{ session }
);
Step 5: Commit the Transaction
Commit the transaction to finalize the changes:
javascript
Copy code
[Link]();
print("Transaction committed successfully.");
Step 6: Handle Errors
Use a try-catch block to manage errors:
javascript
Copy code
try {
[Link]();
const aliceResult = [Link]("test").[Link](
{ accountId: 1, balance: { $gte: 100 } },
{ $inc: { balance: -100 } },
{ session }
);
if (![Link]) {
throw new Error("Insufficient funds in Alice's account.");
const bobResult = [Link]("test").[Link](
{ accountId: 2 },
{ $inc: { balance: 100 } },
{ session }
);
[Link]();
print("Transaction committed successfully.");
} catch (error) {
[Link]();
print("Transaction aborted: " + [Link]);
} finally {
[Link]();
Step 7: Verify the Result
After the transaction, check the balances in the accounts collection:
javascript
Copy code
[Link]().pretty();
Expected Output:
json
Copy code
{ "_id": ObjectId("..."), "accountId": 1, "name": "Alice", "balance": 900 },
{ "_id": ObjectId("..."), "accountId": 2, "name": "Bob", "balance": 600 }
Key Points
1. Ensure Transactions Are Supported: Transactions require a replica set or sharded cluster.
For testing, enable a replica set locally using mongod --replSet rs0.
2. Handle Errors Gracefully: Always include error handling to abort the transaction if an issue
arises.
3. Atomicity: If any step fails (e.g., insufficient funds), the transaction is aborted, leaving the
database in its original state.
This ensures the bank transfer operation is atomic, consistent, isolated, and durable (ACID-
compliant).