You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:57:37