如何用Mongoose正确异步处理MongoDB .save()及多中间件同步?
解决Mongoose多文档插入与中间件同步问题
核心问题分析
- forEach不等待异步操作:你用
data.forEach(async () => {})遍历数组时,forEach不会等待每个异步的document.save()完成,导致第二个[A]文档提前启动插入流程。 - AllTransactions中间件未正确等待异步逻辑:
AllTransactionsSchema.pre("save")里直接调用next(),没有等待Data.findById及后续更新操作完成,导致[B]文档的保存流程提前结束,[C]文档的更新还未完成就开始处理下一个[A]文档。
分步修复方案
1. 用for...of替代forEach确保顺序执行
把遍历数据的代码改成for...of循环,这样每个await document.save()都会等待完成后再处理下一个文档:
for (const transaction of data) { const document = new Transaction({ date: transaction.date, amount: transaction.amount, type: transaction.type, }); await document.save(); }
2. 修复AllTransactions的pre save中间件
将中间件改为async函数,等待所有异步操作完成后再调用next(),同时用for...of替代forEach处理数组的异步操作:
AllTransactionsSchema.pre("save", async function (next) { const Data = this.model("Data"); // 等待findById查询完成 const instance = await Data.findById(/* 填入正确的data id */); // 用for...of确保每个异步操作执行完成 for (const value of instance.values) { // 执行你的更新操作逻辑 // ... await instance.save(); } // 所有操作完成后再进入下一步 next(); });
3. 验证Transaction中间件的异步等待逻辑
你的Transaction中间件已经用了await A_Transaction.save(),这部分没问题,但要确保所有case里的异步保存操作都添加await:
TransactionSchema.pre("save", async function (next) { const allTransactions = this.model("AllTransactions"); var amount = Math.abs(this.amount); switch (this.type) { case "A": const A_Transaction = new allTransactions({ transaction_id: this._id, amount: amount, date: this.date, type: "A", }); await A_Transaction.save(); break; case "B": const B_Transaction = new allTransactions({ transaction_id: this._id, amount: amount, date: this.date, type: "B", }); await B_Transaction.save(); break; case "C": const C_Transaction = new allTransactions({ transaction_id: this._id, amount: amount, date: this.date, type: "C", }); await C_Transaction.save(); break; } next(); });
额外提示
如果业务对数据一致性要求高,可以考虑使用Mongoose事务(Transactions),确保[A]、[B]、[C]文档的操作要么全部成功,要么全部回滚,避免出现部分数据更新的情况。
内容的提问来源于stack exchange,提问作者ilfedevisio
相关产品推荐
相关产品推荐

