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}}, ...Become an O’Reilly member and get unlimited access to this title plus top books and audiobooks from O’Reilly and nearly 200 top publishers, thousands of courses curated by job role, 150+ live events each month,
and much more.
Read now
Unlock full access