When you need to make changes to multiple documents in an all-or-nothing procedure, transactions come in handy. When working with relational databases, it’s usual to separate relevant data amongst different tables in order to normalize the data. As a result, the use of transactions is quite frequent. MongoDB provide you with Transactions that can cater to your above needs.

This article, will introduce you to MongoDB and Nodejs. it will also discuss the MongoDB Transactions and provide you 3 comprehensive steps to perform MongoDB Transactions on Nodejs. Read along to understand the process of connecting to a MongoDB database from a Node.js script, retrieving a list of databases, and printing the results to your console. 

What is MongoDB?

MongoDB Transactions on Nodejs: MongoDb Logo
Image Source

MongoDB is an open-source document-oriented database that is the most popular NoSQL database. ‘NoSQL’ stands for ‘non-relational’. It indicates that MongoDB isn’t built on the table-like structure of relational databases, but instead uses a completely different technique for data storing and retrieval. BSON is the name of the storage format (similar to JSON format).

The MongoDB Compass graphical user interface allows you to interact with the MongoDB database management system. It’s useful because it doesn’t necessitate prior knowledge of MongoDB query syntax. However, MongoDB Compass may be used for more than just displaying data; it can also be used for query optimization, index management, and document validation.

To learn more about MongoDB, visit here.

What are MongoDB Transactions?

MongoDB Transactions on Nodejs: MongoDB Transaction Flowchart
Image Source

The purpose of a transaction is to turn many read-write operations into a single atomic (single) operation. From MongoDB 4.0 forward, transactions are available. For example, if an administrator wants to change the active status of all users, he can use the updateMany or update with’many: true’ options. Every query (updateMany/update) updates all documents; each document’s update is an atomic operation, but the entire process is not.

We choose Transactions because it allows for flexible, rich data modeling with schema validation, multi-document transactions, global encryption, and enterprise-level security. The term “transaction” refers to a situation in which we must do both reads and write operations as a single atomic operation.

What is Nodejs?

MongoDB Transactions on Nodejs: Nodejs Logo
Image Source

Nodejs is a well-known server environment that allows you to work with JavaScript on the server. This open-source tool empowers developers in creating real-time web applications. The Nodejs leverages non-blocking, event-driven Input-Output to provide lightweight yet efficient services in terms of data-intensive real-time applications. Moreover, it allows you to build applications that can run across distributed devices.

Ryan Dahl developed Nodejs in 2009 with the objective of allowing developers to create web servers and networking tools by using JavaScript. Moreover, it allows you to utilize certain modules to manage a collection of core functionalities. These modules and Nodejs API, minimize the complexity of writing server applications. furthermore, you can use Nodejs on macOS, Windows 7, and Linux. The main application of this tool is to build network programs and responsive web applications.

To learn more about Nodejs, visit here.

Steps to Perform MongoDB Transactions on Nodejs

This section utilises the Airbnb Database and aim at leveraging Nodejs for creating a MongoDB transaction that can make reservations in the Airbnb Database. You can easily setup the required MongoDB Transactions on Nodejs using the following steps:

Step 1: Setup the Environment for MongoDB Transactions on Nodejs

First, make sure you have a version of Node.js that is supported. Node 4.x or higher is required for the current version of MongoDB Node.js Driver. You may get it by clicking here: https://nodejs.org/en/download/ 

Next, you need to install the MongoDB Node.js Driver which makes it simple to work with MongoDB databases from Node.js applications. To connect to your database and run the queries you’ll need the driver.

If you don’t already have the MongoDB Node.js Driver installed, use the following command to do so:

npm install mongodb

You can use a pre-built basic template for a Node.js script that accesses an Atlas cluster. Install the required template using the following 4 steps:

  1. Template.js is available for download.
  2. In your preferred code editor, open template.js.
  3. To point to your Atlas cluster, change the Connection URI.
  4. Save the file with the extension transaction.js.

You can run this file in your shell by typing node transaction.js. No output is expected at this point because the file just opens and closes a connection to your Atlas cluster. For the purposes of this post, you can ignore any DeprecationWarnings that appear.

Since the required tools are in lace, you can now create MongoDB Transactions on Nodejs.

Step 2: Create MongoDB Transactions on Nodejs

You can start by creating a helper function that will create a reservation document, which will be useful later. In the transaction.js write the following code:

function newReservationDocument(nameOfListing, reservationDates, reservationDetails) {
      // Create new reservation
      let reservation = {
          name: nameOfListing,
          dates: reservationDates,
      }

      // Add more properties from reservationDetails to the reservation
      for (let detail in reservationDetails) {
          reservation[detail] = reservationDetails[detail];
      }

      return reservation;
  }

The following example will demonstrate the use of the above code (You can call this method from within the main () function):

newReservationDocument("Great Views",
    [new Date("2022-11-13"), new Date("2022-11-14")],
    { pricePerNight: 200, specialRequests: "Late checkout", breakfastIncluded: true });

The following is what the function would return:

{ 
   name: 'Great Views',
   dates: [ 2019-12-31T00:00:00.000Z, 2020-01-01T00:00:00.000Z ],
   pricePerNight: 200,
   specialRequests: 'Late checkout',
   breakfastIncluded: true 
}

Create a Reservation Function

You now have to develop a function that will create a reservation for you in the Airbnb database.

  1. Create an asynchronous method named newReservation while still working in transaction.js. The function should take a MongoClient as a parameter, as well as the user’s email address, the name of the Airbnb listing, the reservation dates, and any other reservation details as shown below.
async function newReservation(client, userEmail, nameOfListing, reservationDates, reservationDetails) {
}
  1. You must now have access to the collections that will be updated in this function. To newReservation, add the following code:
const usersCollection = client.db("sample_airbnb").collection("users");
const listingsAndReviewsCollection = client.db("sample_airbnb").collection("listingsAndReviews");
  1. Now, invoke the helper function developed in the previous section to construct your reservation document. In newReservation() function, paste the following code:
const reservation = newReservationDocument(nameOfListing, reservationDates, reservationDetails);
  1. A session must be associated with each transaction and related processes. Begin a session behind the existing code in newReservation().
const session = client.startSession();
  1. You have the ability to define transaction choices, however, you don’t need to go into those things right now. More information on these options can be found in the driver documentation. Now, Replace the old code in newReservation() with the following:
const transactionOptions = {
    readPreference: 'primary',
    readConcern: { level: 'local' },
    writeConcern: { w: 'majority' }
};
  1. You’re now ready to begin working on your deal. Open a try block beneath the existing code in newReservation(), followed by a catch {} block, and lastly a finally{} block.
try {

} catch(e){

} finally {

}
  1. To start a transaction, perform a callback function, and commit (or abort on fail), we can utilize ClientSession’s withTransaction() method. We must give a method to withTransaction() that will be run inside the transaction. Within try{ }, add a call to withTransaction(). Start by giving withTransaction an anonymous asynchronous function ().
const transactionOutput = await session.withTransaction(async () => {}, transactionOptions);
  1. You are giving an anonymous callback function to withTransaction() that does nothing right now. So, start building the database procedures that you wish to invoke from within that function one by one. To begin, create a reservation in the reservationsarray of the relevant user document. Inside the anonymous function that is being supplied to withTransaction(), paste the following.
const usersUpdateResults = await usersCollection.updateOne(
    { email: userEmail },
    { $addToSet: { reservations: reservation } },
    { session });
console.log(`${usersUpdateResults.matchedCount} document(s) found in the users collection with the email address ${userEmail}.`);
console.log(`${usersUpdateResults.modifiedCount} document(s) was/were updated to include the reservation.`);
  1. You should check if the reservation date is already stated in the listing’s datesReserved array to ensure that an Airbnb listing is not double-booked for any given date. If this is the case, you should cancel the transaction. The update to the user document you made in the previous step will be rolled back if the transaction is aborted. Replace the present code in the anonymous function with the following.
const isListingReservedResults = await listingsAndReviewsCollection.findOne(
    { name: nameOfListing, datesReserved: { $in: reservationDates } },
    { session });
if (isListingReservedResults) {
    await session.abortTransaction();
    console.error("This listing is already reserved for at least one of the given dates. The reservation could not be created.");
    console.error("Any operations that already occurred as part of this transaction will be rolled back.");
    return;
}
  1. The last thing you need to do in your MongoDb Transactions on Nodejs is to add the reservation dates to the listingsAndReviews collection’s datesReserved array. Replace the present code in the anonymous function with the following:
const listingsAndReviewsUpdateResults = await listingsAndReviewsCollection.updateOne(
    { name: nameOfListing },
    { $addToSet: { datesReserved: { $each: reservationDates } } },
    { session });
console.log(`${listingsAndReviewsUpdateResults.matchedCount} document(s) found in the listingsAndReviews collection with the name ${nameOfListing}.`);
console.log(`${listingsAndReviewsUpdateResults.modifiedCount} document(s) was/were updated to include the reservation dates.`);
  1. If the deal goes through, you’ll want to know. You know the transaction was successful if transactionOutput is defined. If transactionOutput is undefined, you will know that you purposely aborted it in the code. Paste the following code beneath the transactionOutput constant’s definition.
if (transactionOutput) {
    console.log("The reservation was successfully created.");
} else {
    console.log("The transaction was intentionally aborted.");
}
  1. Akso. keep track of any errors that occur. Inside the catch(e){ }, paste the following:
console.log("The transaction was aborted due to an unexpected error: " + e);
  1. Whatever occurs, you must call a halt to this meeting. finally, paste the following within { }:
await session.endSession();

This completed the process of setting up MongoDB Transactions on Nodejs.

Step 3: Test the Function Associated with MongoDB Transactions on Nodejs

It’s time to test the new function that you’ve built to create a reservation using a transaction. Make a reservation for Alex for the nights of November 13, 2022 and November 14, 2022 at the “Great Views” listing as follows:

  1. Call your neweReservation() function within main(), beneath the line that reads Make the proper DB calls:
await newReservation(client,
    "alex@example.com",
    "Great Views",
    [new Date("2012-11-13"), new Date("2022-11-14")],
    { pricePerNight: 200, specialRequests: "Late checkout", breakfastIncluded: true });
  1. Save your file.
  2. In your shell, run node transaction.js to run your script.
  3. In your shell, the following output will appear.
1 document(s) found in the users collection with the email address alex@example.com.
1 document(s) was/were updated to include the reservation.
1 document(s) found in the listingsAndReviews collection with the name Great Views.
1 document(s) was/were updated to include the reservation dates.
The reservation was successfully created.

Leslie’s document in the users collection now contains the reservation.

{
"_id": {"$oid":"5dd68bd03712fe11bebfab0c"},
"email": "Alex@example.com",
"name": "Alex",
"reservations": [
    {
    "name": "Great Views", 
    "dates": [
        {"$date": {"$numberLong":"1577750400000"}},
        {"$date": {"$numberLong":"1577836800000"}}
        ],
    "pricePerNight": {"$numberInt":"200"},
    "specialRequests": "Late checkout",
    "breakfastIncluded": true
    }
]
}

The “Great Views” listing in the listingsAndReviews collection now contains the reservation dates.

{
"_id": {"$oid": "5dbc20f942073d6d4dabd730"},
"name": "Alex",
"summary": "Modern home with Great views from the infinity pool",
"property_type": "House",
"bedrooms": {"$numberInt":"6"},
"bathrooms": {"$numberDouble":"4.5"},
"beds": {"$numberInt":"8"},
"datesReserved": [
    {"$date": {"$numberLong": "1577750400000"}},
    {"$date": {"$numberLong": "1577836800000"}}
]
}

That’s it! You now know how to setup MongoDB Transactions on Nodejs and test them.

Conclusion

This article introduced you to MongoDB and Nodejs. It also explained MongoDB Transactions and provided a detailed step-by-step method to set up MongoDB Transactions on Nodejs. The article used an Airbnb Database and developed MongoDB Transactions that will create Airbnb reservations.

Visit our Website to Explore Hevo

MongoDB is a great storage option for your ongoing projects. However, at times, you need to transfer this data to a Data Warehouse for further analysis. Building an in-house solution for this process could be an expensive and time-consuming task Hevo Data, on the other hand, offers a No-code Data Pipeline that can automate your data transfer process, hence allowing you to focus on other aspects of your business like Analytics, Customer Management, etc. This platform allows you to transfer data from 100+ sources like MongoDB to Cloud-based Data Warehouses like Snowflake, Google BigQuery, Amazon Redshift, etc. It will provide you with a hassle-free experience and make your work life much easier.

Want to take Hevo for a spin? Sign Up for a 14-day free trial and experience the feature-rich Hevo suite first hand. 

Share your views on the MongoDB Transactions on Nodejs in the comments section!

Muhammad Faraz
Freelance Technical Content Writer, Hevo Data

In his role as a freelance writer, Muhammad loves to use his analytical mindset and a problem-solving ability to help businesses solve problems by offering extensively researched content.

No Code Data Pipeline For Your Data Warehouse