Atomic Read-Write-Modify: MongoDB’s findAndModify
We’ve already introduced the atomic update modifiers supported by MongoDB. These are very powerful and enable race-free write operations of many kinds—including array manipulation and increment/decrement. However, it is often necessary to be able to modify the document atomically, and also return the result of the atomic operation—in a single step.
For example, imagine a billing system. Each user document has an “account_balance” property. There may be writes which alter the account balance—let’s say an account top-up event which adds money to the account, and a purchase action which takes money from the account. Consider the following implementation:
# User X adds $20 to his/her account, so we atomically increment # account_balance dbh.users.update({"username":username}, {"$inc":{"account_balance":20}}, safe=True) # Fetch the updated account balance to display to user new_account_balance = dbh.users.find_one({"username":username}, {"account_balance":1})["account_balance"]
This will work fine assuming no other writes to the account balance occur between the write and read operations. There is an obvious race condition. If a purchase action were to take place between the balance update and the balance read, the user may be displeased to be presented with a post-payment balance of less than what they expected!
# User X adds $20 to his/her account, so we atomically increment # account_balance dbh.users.update({"username":username}, {"$inc":{"account_balance":20}}, ...
Get MongoDB and Python now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.