Machine Learning & Big Data Blog

Introduction to MongoDB Transactions

3 minute read
Walker Rowe

In computer science there are the concepts ACID (Atomicity, Consistency, Isolation, Durability), atomic, and referential integrity. Which term you know, depends largely on your age. I know the last one, which gives you a clue to hold old I am.

Basically all of these terms mean the same thing: it means the computer should kick out any transaction that would result in a logically-inconsistent set of transactions.

(This article is part of our MongoDB Guide. Use the right-hand menu to navigate.)

Why is this important?

Imagine if you have a sales order and inventory control system. When you make a sale it should reduce on-hand inventory. But what happens if the sales transaction works then the inventory update fails? Then the database would no longer be consistent: the inventory would not match the sales.

The way to avoid that is to group the two transactions into one larger transaction. Oracle database programmers know this as the begin and commit statements. MongoDB supports the same concept, which we illustrate below.

Performance Hit

While MongoDB supports transactions, it stresses that due to performance issues it’s better to embed documents as JSON arrays. In other words, put all the data for one item, and its associated data, into one document.

Oracle programmers would say that results in a database which is not normalized. But that does not matter, as big data databases have gotten rid of that concept, saying it is OK to store the same data in two records, as their focus is on speed and using extra disk space to store something twice does not matter, since storage become cheaper than in the mainframe and Solaris server days.

In other words, its OK to have zip code 29607 and the word Greenville, SC in two records. You do not need to keep a zip code table as a separate entity, as you would with the rdbms approach.

Transactions Illustrated

You need a clustered MongoDB installation to do this, but you can pretend you have a cluster with only server on your laptop. Just pretend that the replicas are offline, by not installing but one node. In other words, follow these instructions we wrote, but remove the section in /etc/mongodConfig.conf as shown below, and only set up one server.

sharding:
clusterRole: configsvr

To use transactions you must have replication turn on and sharding turned off. Support for sharded databases comes with MongoDB 4.2. Below we use 4.0.5.

Create Some Data

Open the mongo shell and create the products and sales collections then add one product to the inventory. We add 100 items of product 123.

use products
db.createCollection("products")
db.createCollection("sales")
db.products.insert({product: 123, count: 100})

Now, sell 4 items of product 123. The result would be 96 items remaining in inventory. So add a sales transaction and update the inventory count to 96 shown below.

Either paste that code into the MongoDB shell or save it in a JavaScript text file and then run it with load(‘<file name>’).

session = db.getMongo().startSession( { readPreference: { mode: "primary" } } );
productsCollection = session.getDatabase("products").products;
salesCollection = session.getDatabase("products").sales;
session.startTransaction( { readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } } );
try {
salesCollection.insertOne( { 
product: 123, 
count: 4
}
);
productsCollection.update(
{ product: 123 },
{ $set:
{
count: 96
}
}
);
} catch (error) {
session.abortTransaction();
throw error;
}
session.commitTransaction();
session.endSession();

Explaining the Code

First, test that is worked:

db.products.findOne();
{
"_id" : ObjectId("5cb8ccb664ae78fe855e9431"),
"product" : 123,
"count" : 96
}

The key parts of the code are:

session.startTransaction( { readConcern: { level: “snapshot” }, writeConcern: { w: “majority” } } ); Start transaction.
session.commitTransaction();

session.endSession();

Commit transaction. It will only reach here if the transactions between the two statements worked because of the try-catch block.
session.abortTransaction() Means do not commit either transaction.
productsCollection.update(
{ product: 123 },
{ $set:
{
count: 96
}
}
)
The format of this is db.collection.update(query to find record, what fields to update).

We update product 123 and set the count to 96.

Troubleshooting

If you are trying to do this with your existing installation and did not turn on replication or turn off sharding or made some illogical statements in your code, you will get any of these errors:

  • Transaction numbers are only allowed on a replica set member or mongos.
  • Multi-document transactions cannot be run in a sharded cluster unless using 4.2.
  • Transactions are only supported in featureCompatibilityVersion 4.0. See http://dochub.mongodb.org/core/4.0-feature-compatibility for more information.

Free e-book: The Beginner’s Guide to MongoDB

MongoDB is the most popular NoSQL database today and with good reason. This e-book is a general overview of MongoDB, providing a basic understanding of the database.


These postings are my own and do not necessarily represent BMC's position, strategies, or opinion.

See an error or have a suggestion? Please let us know by emailing blogs@bmc.com.

BMC Brings the A-Game

BMC works with 86% of the Forbes Global 50 and customers and partners around the world to create their future. With our history of innovation, industry-leading automation, operations, and service management solutions, combined with unmatched flexibility, we help organizations free up time and space to become an Autonomous Digital Enterprise that conquers the opportunities ahead.
Learn more about BMC ›

About the author

Walker Rowe

Walker Rowe is an American freelancer tech writer and programmer living in Cyprus. He writes tutorials on analytics and big data and specializes in documenting SDKs and APIs. He is the founder of the Hypatia Academy Cyprus, an online school to teach secondary school children programming. You can find Walker here and here.