This MongoDB article will help you to get familiar with a two-phase commit in the MongoDB database. We will learn how to perform a two-phase commit in the MongoDB database with the help of some examples.
- MongoDB two-phase commit
- MongoDB two-phase commit example
MongoDB two phase commit
Synopsis
The document provides a pattern for writing data to multiple documents using a two-phase commit approach. It also provides a pattern for doing multi-document updates.
Background
With MongoDB database, The operation performed on single documents are always atomic and operations in which multiple documents are often introduced as “multi-document transactions” are not atomic.
The single document provides the required support for many practical use cases. Since the documents, that contain multiple nested documents can be quite complex.
The following certain issues arise when we execute a transaction composed of sequential operations:
- Atomicity: If one operation fails then the previous operation within the transaction must roll back to the previous state.
- Consistency: If network or hardware interrupts the transaction then the database must be able to recover a consistent state.
We can perform a two-phase commit in our application to multi-document transactions to provide support of multi-document updates. In case of any error, using a two-phase commit ensures that data is constant and the state that preceded the transaction is recoverable.
Read: How to create a new database in MongoDB
MongoDB two phase commit example
In this section, I will explain how to perform a two-phase commit with the help of an example.
Example:
The test scenario is where we transfer the funds from account A to account B. In a relational database system, we subtract the fund from A and add the funds to B in a single multi-statement transaction. So, we follow two-phase commit operations to perform a comparable result.
The following two collections use in this example:
- A colletion named accounts to store account information
- To keep information about fund transfer transactions, there is a collection called transactions.
Insert documents into accounts collection, a document of account A and B.
db.accounts.insert([
{ _id: "A", balance: 1000, pendingTransactions: [] },
{ _id: "B", balance: 1000, pendingTransactions: [] }
])

Insert documents into the transactions collection, a document with transfer information.
Insert a document containing the transfer information into the transactions collection to begin the transfer of 100 from account A to account B. The transaction state is “initial“, and the lastModified field is set to the current date:
db.transactions.insert(
{ _id: 1, source: "A", destination: "B", value: 100, state: "initial", lastModified: new Date() }
)

The documents contain the following fields:
- The
source
and destination fields refer to the _id field from accounts collection. - The value field, which defines the amount of transfer affecting the balance of the source and destination accounts.
- The state field reflects the current state of the transfer.
- The state field can have the value of initial, pending, applied, done, cancelling, and cancelled.
- The lastModified field refers to the last modification date.
Read MongoDB remove an element from the array
Transfer Funds Between Accounts Using Two-Phase Commit
Retrieve the transaction to start
- From the transactions collection find the documents that is in the initial state.
- Currenlty there is only one documents in the transactions collection.
- If the collection contains more documents then the query will return all the transactions with an initial state unless you define additional query conditions.
- The following code used to return the documents where state is initial.
> var t = db.transactions.findOne( { state: "initial" } )
> t

Update transaction state to pending
- Here we use the update() method to update the field value
- We set the transaction state from initial to pending
- Also use the $currentDate operator to set the lastModified field to the current date.
db.transactions.update(
{ _id: t._id, state: "initial" },
{
$set: { state: "pending" },
$currentDate: { lastModified: true }
}
)

The operation returns a writeResult() object with the status of the operation. nMatched and nModified both display 1 after a successful update.
Apply the transaction to both accounts
In this, we apply the transaction t to both accounts using the update() method. In the update condition,
- Include the condition pendingTransactions: {$ne: t._id} to prevent the transaction from being applied twice if the step is repeated.
- Update both the balance field and pendingTransactions field, To apply the transaction to the account.
- Now to update the source account use the below code
db.accounts.update(
{ _id: t.source, pendingTransactions: { $ne: t._id } },
{ $inc: { balance: -t.value }, $push: { pendingTransactions: t._id } }
)
Here, we subtract from its balance the transaction value and add to its pendingTransactions array the transaction _id.
- Now to update the destionation account use the below code
db.accounts.update(
{ _id: t.destination, pendingTransactions: { $ne: t._id } },
{ $inc: { balance: t.value }, $push: { pendingTransactions: t._id } }
)
Here, we added to its balance the transaction value and added to its pendingTransactions array the transaction _id.
To check the documents of the collection use the find() method
db.accounts.find()
Execute both the code in MongoDB Shell:

We successfully updated the transaction of both accounts.
Note: What is the use of $ne?
The $ne operator is used to select documents in which the field value does not equal the provided value. This adds documents that do not contain the field.
Update transaction state to applied
To update the transactions state, we use the update() method
- Set the transactions state to applied and update the lastModified field
db.transactions.update(
{ _id: t._id, state: "pending" },
{
$set: { state: "applied" },
$currentDate: { lastModified: true }
}
)
Now execute the above code in MongoDB Shell and see after updating the documents using the find() method
db.transactions.find()

Here, we successfully updated the documents in the transactions collection.
Update both accounts’ list of pending transactions
In this topic, we remove the applied transaction _id from the
pendingTransactions array for both accounts.
To update the source account use the below code
db.accounts.update(
{ _id: t.source, pendingTransactions: t._id },
{ $pull: { pendingTransactions: t._id } }
)
Use the find() method to see the updated documents of the source account
> db.accounts.find()
{ "_id" : "A", "balance" : 900, "pendingTransactions" : [ ] }
{ "_id" : "B", "balance" : 1100, "pendingTransactions" : [ 1 ] }
To update the destination account use the below code
db.accounts.update(
{ _id: t.destination, pendingTransactions: t._id },
{ $pull: { pendingTransactions: t._id } }
)
Use the find() method to see the updated documents of the destination account
> db.accounts.find()
{ "_id" : "A", "balance" : 900, "pendingTransactions" : [ ] }
{ "_id" : "B", "balance" : 1100, "pendingTransactions" : [ ] }
Now, we successfully update the accounts list of pending transactions.
Update transaction state to done
In this topic, we complete the transaction by setting the state of the transaction to be done and also updating the lastModified field using the below code
db.transactions.update(
{ _id: t._id, state: "applied" },
{
$set: { state: "done" },
$currentDate: { lastModified: true }
}
)
After executing this code in MongoDB Shell, use the find() method to see the document of transactions collection:

We successfully updated the state and lastModified field in the transactions collection.
Using Two-Phase Commits in Production Applications
The example we took above is quite simple. Basically, the purpose of the example is to understand the concept of a two-phase commit in MongoDB.
Production implementations would likely be more complex. Typically, accounts need information about the current balance, pending credits, and pending debits.
Important
Question: Does MongoDB support 2 phase commit?
Answer: The documentation is NOT a definitive design on two-phase commits. And, the key thing to remember here is in reality two-phase commits are technically impossible in MongoDB and I would suggest you get an ACID tech if you want to perform them.
You may also like to read the following article.
- MongoDB backup and restore
- MongoDB find multiple values
- Create index in MongoDB
- MongoDB remove a field from the document
- How does MongoDB create collection
- Pros and cons of MongoDB
- Missing before statement MongoDB
- MongoDB group by multiple fields
- MongoDB drop collection
- MongoDB Auto Increment ID
- Sub-process /usr/bin/dpkg returned an error code (1)
So, in this tutorial, we have learned about the “MongoDB two-phase commit” and we have covered this with an example.
- MongoDB two-phase commit
- MongoDB two-phase commit example
I am Bijay having more than 15 years of experience in the Software Industry. During this time, I have worked on MariaDB and used it in a lot of projects. Most of our readers are from the United States, Canada, United Kingdom, Australia, New Zealand, etc.
Want to learn MariaDB? Check out all the articles and tutorials that I wrote on MariaDB. Also, I am a Microsoft MVP.