Implementing atomic counters in Mongo

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, with the help of previously described findAndModify() command, implementing is quite simple. Refer to the previous recipe Atomic find and modify operations to know what atomic find and modify operations are in Mongo.

Getting ready

Look at the recipe Installing single node MongoDB in Chapter 1, Installing and Starting the Server and start a single instance of Mongo. That 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:
    > 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 identifier is the _id field of the document stored and the value of the counter is stored in the field count. The document passed to the findAndModify operations accepts the query, which uniquely identifies the document storing the current count—a query using the _id field. The update operation is an $inc operation that will increment the value of the count field by 1. But what if the document doesn't exist? This will happen on the first invocation of the counter. To take care of this scenario, we will set the upsert flag to true. The value of count will always start with 1 and there is no way it would accept any user-defined start number for the sequence or a custom increment 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 field new as true.

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

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

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

See also

We can store such common code on a Mongo server that would be available for execution in other functions. Look at the recipe Implementing server-side scripts to see how we can store JavaScript functions on the Mongo server. This allows us even to invoke this function from other programming language clients.

..................Content has been hidden....................

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