Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongo DB 4.0 Transactions With Mongoose & NodeJs, Express

I am developing an application where I am using MongoDB as database with Nodejs + Express in application layer, I have two collections, namely

  1. users
  2. transactions

Here i have to update wallet of thousands of users with some amount and if successful create a new document with related info for each transaction, This is My code :

 userModel.update({_id : ObjectId(userId)}, {$inc : {wallet : 500}}, function (err, creditInfo) {     if(err){         console.log(err);                                 }     if(creditInfo.nModified > 0) {         newTransModel = new transModel({             usersId: ObjectId(userId),                         amount: winAmt,                      type: 'credit',                    });          newTransModel.save(function (err, doc) {             if(err){                 Cb(err);              }         });     }                             }); 

but this solution is not atomic there is always a possibility of user wallet updated with amount but related transaction not created in transactions collection resulting in financial loss.

I have heard that recently MongoDB has added Transactions support in its 4.0 version, I have read the MongoDB docs but couldn't get it to successfully implement it with mongoose in Node.js, can anyone tell me how this above code be reimplemented using the latest Transactions feature of MongoDB which have these functions

Session.startTransaction() Session.abortTransaction() Session.commitTransaction() 

MongoDB Docs : Click Here

like image 747
Gaurav Kumar Avatar asked Jul 08 '18 00:07

Gaurav Kumar


People also ask

Can I use MongoDB and Mongoose together?

yes you should, its a good practice. Mongoose requires a connection to a MongoDB database. You can use require() and connect to a locally hosted database with mongoose.

What are transactions in Mongoose?

Transactions in Mongoose. Transactions are new in MongoDB 4.0 and Mongoose 5.2. 0. Transactions let you execute multiple operations in isolation and potentially undo all the operations if one of them fails.

Can MongoDB be used for transactional applications?

MongoDB added support for multi-document ACID transactions in version 4.0, and MongoDB expanded that support to include distributed transactions in version 4.2. You can implement a transaction in a variety of programming languages using any of MongoDB's official drivers.

Do we have transactions in MongoDB?

For situations that require atomicity of reads and writes to multiple documents (in a single or multiple collections), MongoDB supports multi-document transactions. With distributed transactions, transactions can be used across multiple operations, collections, databases, documents, and shards.


1 Answers

with mongoose in Node.js, can anyone tell me how this above code be reimplemented using the latest Transactions feature

To use MongoDB multi-documents transactions support in mongoose you need version greater than v5.2. For example:

npm install [email protected] 

Mongoose transactional methods returns a promise rather than a session which would require to use await. See:

  • Transactions in Mongoose
  • Blog: A Node.JS Perspective on MongoDB 4.0: Transactions

For example, altering the example on the resource above and your example, you can try:

const User = mongoose.model('Users', new mongoose.Schema({   userId: String, wallet: Number })); const Transaction = mongoose.model('Transactions', new mongoose.Schema({   userId: ObjectId, amount: Number, type: String }));  await updateWallet(userId, 500);  async function updateWallet(userId, amount) {   const session = await User.startSession();   session.startTransaction();   try {     const opts = { session };     const A = await User.findOneAndUpdate(                     { _id: userId }, { $inc: { wallet: amount } }, opts);      const B = await Transaction(                     { usersId: userId, amount: amount, type: "credit" })                     .save(opts);      await session.commitTransaction();     session.endSession();     return true;   } catch (error) {     // If an error occurred, abort the whole transaction and     // undo any changes that might have happened     await session.abortTransaction();     session.endSession();     throw error;    } } 

is not atomic there is always a possibility of user wallet updated with amount but related transaction not created in transactions collection resulting in financial loss

You should also consider changing your MongoDB data models. Especially if the two collections are naturally linked. See also Model data for Atomic Operations for more information.

An example model that you could try is Event Sourcing model. Create a transaction entry first as an event, then recalculate the user's wallet balance using aggregation.

For example:

{tranId: 1001, fromUser:800, toUser:99, amount:300, time: Date(..)} {tranId: 1002, fromUser:77, toUser:99, amount:100, time: Date(..)} 

Then introduce a process to calculate the amount for each users per period as a cache depending on requirements (i.e. per 6 hours). You can display the current user's wallet balance by adding:

  • The last cached amount for the user
  • Any transactions for the user occur since the last cached amount. i.e. 0-6 hours ago.
like image 197
Wan Bachtiar Avatar answered Sep 28 '22 12:09

Wan Bachtiar