Node.jsのmongooseを使用して、最新のトランザクション機能を使用して上記のコードを再実装する方法を教えてもらえますか?
mongooseでMongoDBマルチドキュメントトランザクションサポートを使用するには、v5.2以降のバージョンが必要です。例:
npm install [email protected]
Mongooseトランザクションメソッドは、await
を使用する必要があるセッションではなくpromiseを返します 。参照:
- マングースでの取引
- ブログ:MongoDB 4.0のNode.JSパースペクティブ:トランザクション
たとえば、上記のリソースの例と例を変更して、次のことを試すことができます。
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つのコレクションが自然にリンクされている場合。詳細については、不可分操作のモデルデータも参照してください。
試すことができるモデルの例は、イベントソーシングモデルです。最初にイベントとしてトランザクションエントリを作成し、次に集計を使用してユーザーのウォレット残高を再計算します。
例:
{tranId: 1001, fromUser:800, toUser:99, amount:300, time: Date(..)}
{tranId: 1002, fromUser:77, toUser:99, amount:100, time: Date(..)}
次に、要件に応じて(つまり、6時間ごとに)キャッシュとして期間ごとの各ユーザーの金額を計算するプロセスを導入します。次を追加することで、現在のユーザーのウォレットの残高を表示できます。
- ユーザーの最後にキャッシュされた金額
- ユーザーのトランザクションは、最後にキャッシュされた金額以降に発生します。つまり、0〜6時間前です。