Mongo DB 4.0 交易 Mongoose & NodeJs, Express

Mongo DB 4.0 Transactions With Mongoose & NodeJs, Express

我正在开发一个应用程序,我在应用程序层使用 MongoDB 作为数据库,使用 Nodejs + Express,我有两个集合,即

  1. 用户
  2. 交易

在这里,我必须用一定数量更新数千名用户的钱包,如果成功,则为每笔交易创建一个包含相关信息的新文档,这是我的代码:

 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); 
            }
        });
    }                            
});

但这个解决方案不是atomic总是有可能用户钱包更新了金额但相关交易未在交易收集中创建导致财务损失。

我听说最近 MongoDB 在它的 4.0 version 中添加了 Transactions 支持,我已经阅读了 MongoDB 文档,但无法成功实施它 在 Node.js 中使用 mongoose,谁能告诉我如何使用 MongoDB 的最新 Transactions 功能重新实现上述代码,这些功能具有这些功能

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

MongoDB 文档:Click Here

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

要使用 MongoDB multi-documents transactions support in mongoose,您需要高于 v5.2 的版本。例如:

npm install mongoose@5.2

Mongoose 事务方法 returns 需要使用 await 的承诺而不是会话。参见:

例如,改变上面资源的例子和你的例子,你可以尝试:

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

您还应该考虑更改 MongoDB data models. Especially if the two collections are naturally linked. See also Model data for Atomic Operations 以获取更多信息。

您可以尝试的示例模型是 Event Sourcing model. Create a transaction entry first as an event, then recalculate the user's wallet balance using aggregation

例如:

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

然后引入一个过程,根据需要(即每6小时)计算每个用户每个时段的金额作为缓存。可以通过添加:

来显示当前用户的钱包余额
  • 用户的最后缓存量
  • 用户的任何交易都发生在上次缓存的金额之后。即 0-6 小时前。