アプリケーションレイヤーでNodejs + Expressを使用してデータベースとしてMongoDBを使用しているアプリケーションを開発しています。つまり、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
がTransactions
サポートを4.0 version
、MongoDBのドキュメントを読みましたが、Node.jsでmongooseを使用して正常に実装することができませんでした。上記のコードは、これらの機能を持つMongoDBの最新のTransactions
機能を使用して再実装されます。
Session.startTransaction()
Session.abortTransaction()
Session.commitTransaction()
MongoDB Docs: ここをクリック
node.jsのmongooseで、最新のトランザクション機能を使用して上記のコードを再実装する方法を教えてください
MongoDBマルチドキュメントトランザクション を使用するには mongoose でのサポートが必要です。v5.2以降のバージョンが必要です。例えば:
npm install [email protected]
Mongooseのトランザクションメソッドは、await
を使用する必要があるセッションではなく、promiseを返します。見る:
たとえば、上記のリソースのサンプルとサンプルを変更して、次のことを試すことができます。
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;
}
}
アトミックではありませんが、常にユーザーのウォレットが金額で更新される可能性がありますが、関連するトランザクションはトランザクションコレクションで作成されず、財務上の損失につながります
MongoDB データモデル の変更も検討する必要があります。特に、2つのコレクションが自然にリンクされている場合。詳細については、 アトミック操作のモデルデータ も参照してください。
試すことができるモデルの例は、 Event Sourcing modelです。最初にトランザクションエントリをイベントとして作成し、次に aggregation を使用してユーザーのウォレットの残高を再計算します。
例えば:
{tranId: 1001, fromUser:800, toUser:99, amount:300, time: Date(..)}
{tranId: 1002, fromUser:77, toUser:99, amount:100, time: Date(..)}
次に、要件に応じて(つまり6時間ごとに)キャッシュとして期間ごとに各ユーザーの量を計算するプロセスを導入します。以下を追加することにより、現在のユーザーのウォレットの残高を表示できます。