Skip to content

Instantly share code, notes, and snippets.

@sibu-github
Created July 10, 2022 18:51
Show Gist options
  • Save sibu-github/1fd1f880279da8df270356bc13ef951d to your computer and use it in GitHub Desktop.
Save sibu-github/1fd1f880279da8df270356bc13ef951d to your computer and use it in GitHub Desktop.
Example of transaction in Mongo DB
// transfer balance from one account to another
const transferBalance = async (fromAccount, toAccount, amount) => {
// get database client
const client = await database.getClient();
// create a database session
const session = client.startSession();
// define transaction options
const transactionOptions = {
readPreference: 'primary',
readConcern: { level: 'local' },
writeConcern: { w: 'majority' }
};
// since transaction can throw error it must be executed within a try catch bolck
try {
// withTransaction takes a function as argument,
// the function must be an async function
// if the function throws any error then all operations are rollbacked
// and transaction is aborted.
// we can also call the abortTransaction explicitly to rollback the transaction as well.
const transactionResult = await session.withTransaction(async () => {
const accountCollection = client.db('mydb').collection('accounts');
const transactionLogCollection = client.db('mydb').collection('transactionLog');
// update fromAccount and decrement balance
let updateResult = await accountCollection.updateOne({"accountNo": fromAccount}, {
$inc: {balance: -1 * amount},
$set: {updateTimestamp: utils.getCurrentTimestamp()}
}, {session}
);
// NOTE: WE MUST PASS THE session object to the above updateOne statement
// so that it executes within the session.
if (updateResult.modifedCount !== 1){
// update did not happen properly, abort transaction
await session.abortTransaction();
return;
}
// update toAccount and increment balance
updateResult = await accountCollection.updateOne({"accountNo": toAccount}, {
$inc: {balance: amount},
$set: {updateTimestamp: utils.getCurrentTimestamp()}
}, {session}
);
// NOTE: WE MUST PASS THE session object to the above updateOne statement
// so that it executes within the session.
if (updateResult.modifedCount !== 1){
// update did not happen properly, abort transaction
await session.abortTransaction();
return;
}
// insert the data into the transactionLog
await transactionLogCollection.insertOne({
fromAccount,
toAccount,
amount,
createdTimestamp: utils.getCurrentTimestamp()
});
},transactionOptions);
// if the transaction was aborted then transactionResult will have undefined value
// otherwise it will hold some value which is the return value of the last statement
// executed within the transaction
// check the transactionResult value here and return appropriate response
if(!transactionResult) {
console.error("transaction is aborted");
return false;
}
return true;
} catch(err){
// log the error or return error response from here
console.error(err);
return false;
} finally{
// we must always call endSession
// thats why it is put inside finally block
await session.endSession();
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment