Atomic find and modify operations

In Chapter 2, Command-line Operations and Indexes, we had some recipes that explained various CRUD operations that we perform in MongoDB. There was one concept that we didn't cover that is, atomically finding and modifying documents. Modify consists of both update and delete operations. In this recipe, we will see find and modify operations in some detail and, in the next recipe, Implementing atomic counters in MongoDB, we will put them to use in implementing counters.

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 MongoDB. That is the only prerequisite for this recipe. Start a Mongo shell and connect to the started server.

How to do it…

We will test a document in the atomicOperationsTest collection as follows:

  1. Execute the following commands from the Mongo shell:
    > db.atomicOperationsTest.drop()
    > db.atomicOperationsTest.insert({i:1})
    
  2. Execute the following commands from the Mongo shell and observe the output:
    > db.atomicOperationsTest.findAndModify({
        query: {i: 1},
        update: {$set : {text : 'Test String'}},
        new: false
      }
    )
    
  3. We will execute another one this time, but with slightly different parameters; observe the output this time around:
    > db.atomicOperationsTest.findAndModify({
        query: {i: 1},
        update: {$set : {text : 'Updated String'}}, fields: {i: 1, text :1, _id:0},
        new: true
      }
    )
    
  4. We will execute another update this time that will upsert the document as follows:
    > db.atomicOperationsTest.findAndModify({
        query: {i: 2},
        update: {$set : {text : 'Test String'}},
        fields: {i: 1, text :1, _id:0},
        upsert: true,
        new: true
      }
    )
    
  5. Now query the collection once, as follows, and see the documents present:
    > db.atomicOperationsTest.find().pretty()
    
  6. We will finally execute the delete operation as follows:
    > db.atomicOperationsTest.findAndModify({
        query: {i: 2},
        remove: true,
        fields: {i: 1, text :1, _id:0},
        new: false
      }
    )
    

How it works…

If we perform the find and update operations independently by first finding the document and then updating it in MongoDB, the results might not be as expected as there might be an interleaving update between the find and the update operations that will change the document state. In some of the specific use cases, such as implementing atomic counters, this is not acceptable and thus, we need a way to atomically find, update, and return a document. The returned value is either the one before the update is applied or after the update is applied, and this is decided by the invoking client.

Now that we have executed the steps in the preceding section, let us see what we actually did and what all these fields in the JSON document, which are passed as parameters to the findAndModify operation, mean. Starting with step 2, we gave a document as a parameter to the findAndModify function that contains the following fields. The fields query, update, and new are used to specify the query that will be used to find the document, the update that will be applied to it, and a Boolean value that will be used to specify whether the document returned by the operation is the one after the update is applied or before it was applied. In this case, the value of the new flag is false. The resulting document returned is the one before the update is applied.

In step 3, we actually added a new field to the document, passed as a parameter called fields, that is used to select a limited set of fields from the resulting document returned. Also, the value of the new field is true, which indicates that we want the updated document; that is, the one after the update operation is executed and not the one before the update.

In step 4, the parameter contained a new field called upsert, which upserted (update + insert) the document. That is, if the document with the given query is found, it is updated; otherwise, a new one is created and updated. If the document didn't exist and an upsert happens, having the value of the new parameter as false will return null. This is because there was nothing present before the update operation was executed.

Finally, in step 6, the parameter didn't have the update field but had the remove field with the value true, indicating that the document is to be removed. Also, the value of the new field was false, which means that we expect the document that got deleted.

See also

  • The Implementing atomic counters in MongoDB recipe, to see how to implement the use case that is used to develop an atomic counter in Mongo
..................Content has been hidden....................

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