Learning MongoDB

0% completed

Previous
Next
Transactions in MongoDB

Transactions in MongoDB allow multiple operations to be executed in a single atomic unit of work. This ensures that all operations within a transaction either complete successfully or none of them do, maintaining data consistency.

MongoDB transactions are designed to follow the ACID properties:

  • Atomicity
  • Consistency
  • Isolation
  • Durability

Atomicity

Atomicity ensures that all the operations within a transaction are completed successfully. If any operation fails, the entire transaction fails, and the database state is left unchanged. This property is crucial for maintaining consistency, especially in scenarios involving multiple related operations.

Example: Imagine transferring $50 from Alice's account to Bob's account. Both operations (debiting Alice's account and crediting Bob's account) must succeed or fail together.

Consistency

Consistency ensures that a transaction brings the database from one valid state to another, maintaining the integrity of the database. This means that any data written to the database must be valid according to all defined rules, including constraints, cascades, and triggers.

Example: In our example, the balance of Alice's and Bob's accounts should remain consistent before and after the transaction. If Alice's balance is debited and Bob's balance is credited correctly, the database remains consistent.

Isolation

Isolation ensures that the operations within a transaction are isolated from other operations. This means that intermediate states of a transaction are not visible to other operations, ensuring that concurrent transactions do not interfere with each other.

Example: If another transaction tries to read the balance of Alice or Bob while our transaction is in progress, it will not see the intermediate state where only one account is updated.

Durability

Durability ensures that once a transaction has been committed, it will remain so, even in the event of a system failure. This guarantees that the changes made by the transaction are permanently applied to the database.

Example: Once the transaction for transferring $50 from Alice to Bob is committed, the changes are permanent and will persist even if the system crashes immediately afterward.

Example

Inserting Data in MongoDB

Execute the below query to add data to the MongoDB database.

db.users.insertMany([ { _id: 1, name: "Alice", balance: 100 }, { _id: 2, name: "Bob", balance: 200 } ]) db.accounts.insertMany([ { _id: 1, userId: 1, accountType: "savings", balance: 100 }, { _id: 2, userId: 2, accountType: "checking", balance: 200 } ])

NodeJS Set Up

Let's create a Node.js script to demonstrate a transaction. You can refer to the MongoDB With NodeJS chapter to get in-depth guide about setting up MongoDB environment with NodeJS.

The script will transfer $50 from Alice's account to Bob's account.

Step 1: Setting Up Node.js

First, ensure you have Node.js installed. Initialize a new project and install the MongoDB driver:

npm init -y npm install mongodb

Step 2: Creating the Transaction Script

Create a file named transaction.js and add the following code:

const { MongoClient } = require("mongodb"); async function run() { // Connection URI const uri = "mongodb://localhost:27017"; // Create a new MongoClient const client = new MongoClient(uri); try { // Connect to the MongoDB cluster await client.connect(); // Specify the database and collections const database = client.db("bank"); const users = database.collection("users"); const accounts = database.collection("accounts"); // Start a session const session = client.startSession(); // Start a transaction session.startTransaction(); try { // Update Alice's balance by subtracting $50 const aliceUpdate = await users.updateOne( { _id: 1 }, { $inc: { balance: -50 } }, { session } ); // Check if Alice's document was found and updated if (aliceUpdate.matchedCount === 0) { throw new Error("Alice's document not found"); } // Update Bob's balance by adding $50 const bobUpdate = await users.updateOne( { _id: 2 }, { $inc: { balance: 50 } }, { session } ); // Check if Bob's document was found and updated if (bobUpdate.matchedCount === 0) { throw new Error("Bob's document not found"); } // Commit the transaction await session.commitTransaction(); console.log("Transaction committed."); } catch (error) { // If any error occurred, abort the transaction console.log("Transaction aborted. Error:", error); await session.abortTransaction(); } finally { // End the session session.endSession(); } } finally { // Close the client connection await client.close(); } } run().catch(console.dir);

Explanation of Node.js Code

  1. Connecting to MongoDB: The script connects to the MongoDB server using the MongoClient.
const uri = "mongodb://localhost:27017"; const client = new MongoClient(uri); await client.connect();
  1. Starting a Session: A session is started using client.startSession(), which is necessary for managing the transaction.
const session = client.startSession();
  1. Starting a Transaction: The transaction begins with session.startTransaction().
session.startTransaction();
  1. Performing Operations: Updates are performed within the transaction. If any operation fails, the transaction is aborted, and all changes are rolled back.
const aliceUpdate = await users.updateOne( { _id: 1 }, { $inc: { balance: -50 } }, { session } ); if (aliceUpdate.matchedCount === 0) { throw new Error("Alice's document not found"); } const bobUpdate = await users.updateOne( { _id: 2 }, { $inc: { balance: 50 } }, { session } ); if (bobUpdate.matchedCount === 0) { throw new Error("Bob's document not found"); }
  1. Committing the Transaction: If all operations succeed, the transaction is committed with session.commitTransaction().
await session.commitTransaction();
  1. Error Handling: If any error occurs, the transaction is aborted with session.abortTransaction(), ensuring that no partial changes are applied.
catch (error) { console.log("Transaction aborted. Error:", error); await session.abortTransaction(); }
  1. Ending the Session: The session is ended with session.endSession(), and the client connection is closed to free up resources.
finally { session.endSession(); await client.close(); }

Use Cases or Benefits

  1. Data Consistency: Transactions ensure data consistency across multiple operations, making them ideal for financial applications, inventory systems, and any application requiring atomic operations.
  2. Complex Workflows: Transactions simplify complex workflows that involve multiple collections and operations.
  3. Error Handling: Provides a mechanism to handle errors gracefully, ensuring partial updates do not leave the database in an inconsistent state.

Considerations

  1. Performance Overhead: Transactions can introduce performance overhead, so they should be used judiciously.
  2. Distributed Transactions: MongoDB supports transactions across multiple documents and collections but not across multiple databases.
  3. Locks: Transactions may acquire locks on documents, potentially impacting concurrency.

Transactions in MongoDB provide a robust mechanism for ensuring data consistency and integrity across multiple operations. By following the ACID properties, MongoDB transactions ensure that all operations within a transaction are completed successfully or not at all. This lesson covered the basics of transactions, their syntax, practical examples, use cases, and considerations, providing a comprehensive understanding of how to implement and use transactions in MongoDB effectively.

.....

.....

.....

Like the course? Get enrolled and start learning!
Previous
Next