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

MongoDB按条件分组:如何统计包含虚拟逾期状态的各类型任务数量

解决方案

可以通过MongoDB聚合管道的动态字段计算能力实现需求,无需修改原有Schema,具体实现如下:

核心思路

  • 先通过$addFields阶段动态生成计算后的统计状态,包含Overdue的判断逻辑
  • 再按状态、任务类型两级分组统计数量
  • 最后格式化输出为要求的结构,补全数量为0的类型

完整实现代码

const Task = mongoose.model('Task', taskSchema);
const currentTime = new Date();
// 定义所有需要统计的任务类型,用于后续补全0值
const ALL_TYPES = ['Call Back', 'Visit', 'Meet', 'Site'];
// 定义所有需要统计的状态
const ALL_STATUS = ['Pending', 'Completed', 'Overdue'];

const stats = await Task.aggregate([
  // 第一步:动态计算统计用的状态
  {
    $addFields: {
      statsStatus: {
        $cond: {
          if: {
            $and: [
              { $eq: ['$status', 'Pending'] },
              { $lt: ['$due_date', currentTime] },
              // 排除due_date为空的场景
              { $ne: ['$due_date', null] },
              { $ne: ['$due_date', ''] }
            ]
          },
          then: 'Overdue',
          else: '$status'
        }
      }
    }
  },
  // 第二步:按统计状态+任务类型分组计数
  {
    $group: {
      _id: {
        status: '$statsStatus',
        type: '$type'
      },
      count: { $sum: 1 }
    }
  },
  // 第三步:按状态聚合,把同状态下的所有类型计数拼成对象
  {
    $group: {
      _id: '$_id.status',
      typeCounts: {
        $push: {
          k: '$_id.type',
          v: '$count'
        }
      }
    }
  },
  // 第四步:转成要求的键值结构
  {
    $replaceRoot: {
      newRoot: {
        $arrayToObject: [[
          {
            k: '$_id',
            v: { $arrayToObject: '$typeCounts' }
          }
        ]]
      }
    }
  }
]);

// 补全所有状态和类型的默认0值(聚合只会返回有数据的条目,缺失的需要手动补)
const result = Object.assign({}, ...stats);
ALL_STATUS.forEach(status => {
  if (!result[status]) result[status] = {};
  ALL_TYPES.forEach(type => {
    if (result[status][type] === undefined) {
      result[status][type] = 0;
    }
  });
});

执行完上述代码后,result就是你要求的输出格式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 00:36:05