异步查询完成后返回每小时生产计数结果的问题求助
问题分析与解决方案
你的问题核心是异步操作的执行时机没把握好——你在所有数据库查询还没完成的时候就返回了响应,这时候productionCount自然是空的。另外代码里还有几个小错误,我帮你一步步修正:
关键问题点
- 你在
async.each的异步任务还全部完成前,就调用了res.json,这是典型的异步顺序错误 - 迭代
data数组时,错误地使用了data.from(整个数组的属性),而不是当前迭代的单个时间区间对象的from和to - 多余使用了
async.waterfall,这里只需要单次异步查询,没必要用瀑布流 - 时间区间的循环计算有问题,会导致所有时间戳指向同一个对象(因为Date是引用类型)
修正后的完整代码
exports.production_report = function(req, res) { ShiftTiming.findOne({"clientId": req.body.clientId}, function (err, shiftTiming) { if (err) { return res.send(err); } const data = []; const productionCount = []; const baseDate = new Date(req.body.eDate); // 正确生成24个小时的时间区间 for (let i = 0; i <= 23; i++) { // 每次循环都创建新的Date对象,避免引用覆盖 const from = new Date(baseDate); // 按你的逻辑计算基础小时和分钟(适配shiftA的结构) const baseHour = shiftTiming.shiftA[0] + shiftTiming.shiftA[1]; const baseMinute = shiftTiming.shiftA[3] + shiftTiming.shiftA[4]; from.setHours(baseHour + i); from.setMinutes(baseMinute); const to = new Date(from); to.setHours(to.getHours() + 1); data.push({"from": from, "to": to}); } // 使用async.each处理所有异步查询 async.each(data, function(timeRange, callback) { // 查询当前时间区间的计数,使用当前迭代的timeRange的from和to CycleTime.count({ "machineId": req.body.machineId, "startDateTime": { $gte: timeRange.from, $lt: timeRange.to } }).exec(function(err, count) { if (err) { return callback(err); // 传递错误给async.each的回调 } productionCount.push({count}); callback(); // 标记当前迭代任务完成 }); }, function(err) { // 所有异步任务完成后的回调 if (err) { return res.send(err); } // 现在productionCount已经填充完成,返回响应 res.json({ data: data, productionCount: productionCount }); }); }); };
核心修改说明
- 异步流程控制:把
res.json移到async.each的最终回调里,确保所有数据库查询完成后再返回数据 - 迭代参数修正:在
async.each的迭代函数里,使用当前的timeRange(代替你原来的user)来获取单个时间区间的from和to,而不是错误地引用整个data数组 - 时间对象创建:每次循环都创建新的
Date对象,避免因为Date是引用类型导致所有时间区间被覆盖的问题 - 简化异步逻辑:移除了多余的
async.waterfall,因为这里只需要执行一次异步查询,不需要多步骤的瀑布流操作 - 错误处理优化:在每个异步步骤都正确传递错误,确保错误能被捕获并返回给客户端
测试验证
当你用示例请求调用这个接口时,productionCount会被填充为对应每个时间区间的计数,和data数组的元素一一对应。
内容的提问来源于stack exchange,提问作者Jayesh Rohira
相关产品推荐
相关产品推荐

