mongoose.create在async.each循环内无法保存文档问题
看起来你遇到了两个核心问题:自动创建的Entry没有保存到数据库,以及Plan的planEntries数量异常增长。让我们一步步拆解并解决这些问题:
问题1:自动创建的Entry未保存到数据库
原因:你的代码里在修改Entry属性后调用了entry.save(),但这是异步操作——你直接紧接着调用了next(),没有等待save完成就进入下一次循环。这可能导致save操作还没完成,Node.js就已经开始处理下一个迭代,甚至因为事件循环调度导致save失败。另外你连续调用了两次entry.save(),这不仅冗余,还可能引发数据不一致。
解决方案:
- 先一次性设置好
Entry的所有属性,再仅调用一次entry.save() - 在
entry.save()的回调函数里调用next(),确保异步操作完成后再推进循环
问题2:Plan的planEntries数量异常暴涨
原因:你在async.each的每个迭代里都调用了foundPlan.save(),而save是异步的。当多个迭代同时执行时,前一个save还没完成(Plan还没更新到数据库),后一个迭代又把新的Entry推到foundPlan.planEntries并再次调用save,这会导致同一个Entry被多次push到数组中,最终让numEntries远超预期。
解决方案:
- 不要在循环中每次都保存Plan,而是等所有Entry都创建并push到
foundPlan.planEntries之后,在async.each的最终回调里统一保存Plan一次。这样既避免了重复保存,又提升了性能。
修改后的完整路由代码
// Auto-populate entries router.post("/populate", middlewareObj.isLoggedIn, function(req, res) { let orgList = []; console.log(req.body.orgs); if (typeof req.body.orgs === 'string') { orgList = [req.body.orgs]; } else { orgList = req.body.orgs || []; // 增加空值处理,避免潜在查询错误 } // 移除无效的orgList.save()(数组没有save方法) console.log(orgList); // lookup Plan using ID Plan.findById(req.params.id, function(err, foundPlan) { if (err) { console.log(err); return res.redirect("/plans"); } BaseData.find({ "contributingRegion": foundPlan.contributingRegion, "org": { $in: orgList } }, function(err, baseData) { if (err) { console.log(err); return res.redirect("/plans"); } console.log(baseData.length); // Create entries & push into plan async.each(baseData, function(data, next) { Entry.create(data, function(err, entry) { if (err) { return next(err); } // 一次性设置所有Entry属性 entry.author.id = req.user._id; entry.author.username = req.user.username; entry.adjHC = entry.initHC; entry.adjResRate = entry.initResRate; entry.yr1Resignations = Math.round(entry.adjHC * entry.adjResRate); entry.yr1Supply = entry.adjHC - entry.yr1Resignations; entry.yr2Resignations = Math.round(entry.yr1Supply * entry.adjResRate); entry.yr2Supply = entry.yr1Supply - entry.yr2Resignations; entry.yr3Resignations = Math.round(entry.yr2Supply * entry.adjResRate); entry.yr3Supply = entry.yr2Supply - entry.yr3Resignations; entry.yr4Resignations = Math.round(entry.yr3Supply * entry.adjResRate); entry.yr4Supply = entry.yr3Supply - entry.yr4Resignations; entry.yr5Resignations = Math.round(entry.yr4Supply * entry.adjResRate); entry.yr5Supply = entry.yr4Supply - entry.yr5Resignations; entry.demandYr0 = entry.adjHC; entry.demandYr1 = entry.adjHC; entry.demandYr2 = entry.adjHC; entry.demandYr3 = entry.adjHC; entry.demandYr4 = entry.adjHC; entry.demandYr5 = entry.adjHC; entry.gapYr1 = entry.yr1Supply - entry.demandYr1; entry.gapYr2 = entry.yr2Supply - entry.demandYr2; entry.gapYr3 = entry.yr3Supply - entry.demandYr3; entry.gapYr4 = entry.yr4Supply - entry.demandYr4; entry.gapYr5 = entry.yr5Supply - entry.demandYr5; // 等待save完成后再推进循环 entry.save(function(err) { if (err) { return next(err); } console.log(entry._id + ' saved'); // 只push到数组,不在这里保存Plan foundPlan.planEntries.push(entry); next(); }); }); }, function(err) { // 所有Entry都创建完成后,统一保存Plan if (err) { console.log(err); return res.redirect("/plans"); } foundPlan.save(function(err) { if (err) { console.log(err); return res.redirect("/plans"); } res.redirect('/plans/' + foundPlan._id); }); }); }); }); });
额外优化建议
- 可以考虑使用
async/await替代async.each,代码会更易读,异步流程也更清晰 - 给所有数据库查询增加错误处理的返回逻辑(比如
return res.redirect),避免后续代码无意义执行 - 对
req.body.orgs增加空值判断,防止orgList变成undefined导致查询出错
内容的提问来源于stack exchange,提问作者KevinD
相关产品推荐
相关产品推荐

