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

Mongoose遍历数组元素执行查询异步未等待返回空的解决方法

问题根因

代码返回结果不符合预期的核心原因:forEach 遍历不会等待内部的异步 Reviews.find() 查询执行完成,外层Promise链在启动所有评论查询任务后,会立刻执行 return res.json(result) 逻辑,此时所有评论查询还未返回结果,result 数组自然无法拿到完整填充的数据。

可行实现方案

方案1:通过Promise.all等待所有异步任务执行完成

用map遍历生成所有查询对应的Promise实例,再通过Promise.all等待所有查询全部返回后,再组装结果返回,代码如下:

Service.find(query)
  .then(async (servicesList) => {
    const taskList = servicesList.map(async (service) => {
      const revs = await Reviews.find({ service: service._id });
      service.reviews = revs;
      return service;
    });
    const result = await Promise.all(taskList);
    return res.json(result);
  })
  .catch((err) => {
    return res.json({});
  });

注意:不要在异步场景下用forEach配合外部数组push收集结果,这种写法无法追踪异步任务的执行状态,还可能出现结果顺序错乱的问题。

方案2:批量查询替代循环单查(性能更优,推荐)

循环给每个元素单独发起查询属于典型的N+1查询问题,数据量稍大时性能很差,推荐用批量查询的方式优化,仅需2次数据库查询即可完成数据组装:

Service.find(query)
  .then(async (servicesList) => {
    // 提取所有服务ID
    const serviceIdList = servicesList.map(item => item._id);
    // 一次性查询所有服务关联的评论
    const allReviews = await Reviews.find({ service: { $in: serviceIdList } });
    // 按服务ID对评论分组
    const reviewGroup = {};
    allReviews.forEach(review => {
      if (!reviewGroup[review.service]) {
        reviewGroup[review.service] = [];
      }
      reviewGroup[review.service].push(review);
    });
    // 给每个服务挂载对应评论
    const result = servicesList.map(service => {
      service.reviews = reviewGroup[service._id] || [];
      return service;
    });
    return res.json(result);
  })
  .catch((err) => {
    return res.json({});
  });

如果你的Mongoose模型已经配置了关联引用,也可以直接用内置的populate方法实现连表查询,代码更简洁,性能也更好:

// 需提前在Service模型上配置reviews虚拟字段关联Reviews模型,或在Reviews模型的service字段配置ref指向Service模型
Service.find(query)
  .populate('reviews')
  .then(result => res.json(result))
  .catch(err => res.json({}));

内容的提问来源于stack exchange,提问作者Deli

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 19:57:31