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

Node.js异步场景下数组push后打印为空的问题求助

Node.js OrderPlace接口meta数组为空问题解决办法

问题描述

编写Node.js的OrderPlace接口时,从请求体获取product_info数组并初始化空数组meta;遍历product_info,通过Ticket.find查询数据库,满足条件时向meta中push包含cart_id、pro_id、quantity的对象,但最终console.log(meta)输出为空,无法得到预期的数组数据。

原代码:

exports.OrderPlace = (req, res) => {
  const all_product = req.body.product_info;
  let meta = [];
  all_product.forEach((element) => {
    Ticket.find({ _id: element.product_id }, function (err, docs) {
      if (err) return handleError(err);
      if (docs[0]._id == element.product_id) {
        if (element.quantity < docs[0].quantity) {
          meta.push({
            cart_id: element.id,
            pro_id: element.product_id,
            quantity: element.quantity + " Asking quentity is not available!",
          });
        }
      }
    });
  });
  console.log(meta);
};

问题原因

  1. 异步执行顺序问题:Ticket.find是异步数据库操作,forEach会快速遍历完所有元素,但此时所有数据库查询还未完成,console.log(meta)就已经执行,所以meta还是空数组。
  2. 冗余判断:查询条件是_id: element.product_id,如果查询到数据,docs[0]._id必然和element.product_id匹配,无需额外判断。
  3. 拼写错误:quentity应为quantity。

解决方案

方案一:用async/await + for...of(串行处理)

将接口函数声明为async,使用for...of遍历数组(支持异步等待),确保每个数据库查询完成后再处理下一个:

exports.OrderPlace = async (req, res) => {
  const all_product = req.body.product_info;
  let meta = [];
  
  for (const element of all_product) {
    try {
      // 用findOne代替find,按_id查询仅返回单个文档
      const doc = await Ticket.findOne({ _id: element.product_id });
      
      if (doc) {
        if (element.quantity < doc.quantity) {
          meta.push({
            cart_id: element.id,
            pro_id: element.product_id,
            quantity: `${element.quantity} Asking quantity is not available!`
          });
        }
      }
    } catch (err) {
      handleError(err);
      // 可选:出现错误时直接返回响应
      // return res.status(500).json({ error: err.message });
    }
  }
  
  console.log(meta);
  // 记得返回接口响应
  res.status(200).json(meta);
};

方案二:用Promise.all(并行处理,效率更高)

将所有数据库查询包装成Promise数组,用Promise.all并行执行,等待所有查询完成后再处理结果:

exports.OrderPlace = async (req, res) => {
  const all_product = req.body.product_info;
  
  // 生成所有查询的Promise
  const queryPromises = all_product.map(async (element) => {
    try {
      const doc = await Ticket.findOne({ _id: element.product_id });
      // 满足条件时返回对象,否则返回null
      if (doc && element.quantity < doc.quantity) {
        return {
          cart_id: element.id,
          pro_id: element.product_id,
          quantity: `${element.quantity} Asking quantity is not available!`
        };
      }
      return null;
    } catch (err) {
      handleError(err);
      return null;
    }
  });
  
  // 等待所有Promise完成,过滤掉null值得到最终meta
  const meta = (await Promise.all(queryPromises)).filter(item => item !== null);
  
  console.log(meta);
  res.status(200).json(meta);
};

额外说明

  • 使用findOne替代find:按_id查询MongoDB只会返回单个文档,findOne直接返回文档对象,无需取docs[0],更简洁高效。
  • 完善错误处理:异步操作必须捕获错误,避免未处理的Promise异常导致程序崩溃。
  • 补充响应返回:原代码缺少接口响应,需添加res.status(...).json(...)语句,否则客户端会一直处于等待状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 13:46:05