Skip to content

Instantly share code, notes, and snippets.

@drenther
Last active September 21, 2021 13:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save drenther/23b9a4c9591ce2b19309e11a747d6624 to your computer and use it in GitHub Desktop.
Save drenther/23b9a4c9591ce2b19309e11a747d6624 to your computer and use it in GitHub Desktop.
A gettings started example for mongoose transactions
const mongoose = require('mongoose');
// the run-rs command will by default start the replica sets on the following ports
const dbUri = 'mongodb://localhost:27017,localhost:27018,localhost:27019/example';
async function init() {
// connecting the DB
await mongoose.connect(dbUri, { replicaSet: 'rs' });
// a simple mongoose model
const User = mongoose.model('User', new mongoose.Schema({
accountId: String, name: String, balance: Number
)};
User.createCollection();
// creating two users
await User.create([
{ accountId: 'ACC001', name: 'John', balance: 50.00 },
{ accountId: 'ACC002', name: 'Jane', balance: 50.00 }
]);
}
module.exports = init;
const mongoose = require('mongoose');
// for currency calculation handling
const $ = require('currency.js');
const init = require('./init');
async function handleMoneyTransfer(senderAccountId, receiveAccountId, amount) {
// connect the DB and get the User Model
const User = await init();
const session = await mongoose.startSession();
session.startTransaction();
try {
// always pass session to find queries when the data is needed for the transaction session
const sender = await User.findOne({ accountId: senderAccountId }).session(session);
// calculate the updated sender balance
sender.balance = $(sender.balance).subtract(amount);
// if funds are insufficient, the transfer cannot be processed
if (sender.balance < 0) {
throw new Error(`User - ${sender.name} has insufficient funds`);
}
// save the sender updated balance
// do not pass the session here
// mongoose uses the associated session here from the find query return
// more about the associated session ($session) later on
await sender.save();
const receiver = await User.findOne({ accountId: receiverAccountId }).session(session);
receive.balance = $(receiver.balance).add(amount);
await receiver.save();
// commit the changes if everything was successful
await session.commitTransaction();
} catch (error) {
// if anything fails above just rollback the changes here
// this will rollback any changes made in the database
await session.abortTransaction();
// logging the error
console.error(error);
// rethrow the error
throw error;
} finally {
// ending the session
session.endSession();
}
}
@aayushdutt
Copy link

There an async missing in the handleMoneyTransfer function.

@drenther
Copy link
Author

Yea, thanks for pointing it out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment