Implementing atomic counters in MongoDB

Atomic counters are a necessity for a large number of use cases. Mongo doesn't have a built-in feature for atomic counters; nevertheless, it can be easily implemented using some of its cool offerings. In fact, implementing it is merely a couple of lines of code. Refer to the previous recipe to know what atomic find and modify operations are in Mongo.

Getting ready

Refer to the Single node installation of MongoDB recipe in Chapter 1, Installing and Starting the MongoDB Server, and start a single instance of Mongo. This is the only prerequisite for this recipe. Start a Mongo shell and connect to the started server.

How to do it…

  1. Execute the following piece of code from the Mongo shell:
    > function getNextSequence(counterId) {
      return db.counters.findAndModify(
        {
          query: {_id : counterId},
          update: {$inc : {count : 1}},
          upsert: true,
          fields:{count:1, _id:0},
          new: true
        }
      ).count
    }
    
  2. Now, from the shell, invoke the following commands:
    > getNextSequence('Posts Counter')
    > getNextSequence('Posts Counter')
    > getNextSequence('Profile Counter')
    

How it works…

The function is as simple as a findAndModify operation on a collection used to store all the counters. The counter ID is the _id field of the document stored, and the value of the counter is stored in the count field. The document passed to findAndModify accepts the query that uniquely identifies the document storing the current count, which is a query using the _id field. The update operation is an $inc operation that will increment the value of the count field by one, but what if the document doesn't exist? This will happen during the first invocation of the counter. To take care of this scenario, we will be setting the upsert flag to true, which atomically either updates the document field or creates one. The value, thus, will always start with one, and there are no ways in this function by which we can have any user-defined start number for the sequence and a custom-incremented step. To address such requirements, we will have to specifically add a document with the initialized values to the counters collection. Finally, we are interested in the state of the counter after the value is incremented. Hence, we set the value of the new field as true.

On invoking this method three times, as we did, we should see the following in the counters collection. Simply execute the following query:

> db.counters.find()
{ "_id" : "Posts Counter", "count" : 2 }
{ "_id" : "Profile Counter", "count" : 1 }

Using this small function, we have now implemented atomic counters in Mongo.

We can store such common code on the Mongo server, which will be available for execution in other functions.

See also

  • The Implementing server-side scripts recipe to see how we can store JavaScript functions on the Mongo server
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset