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

MongoDB聚合管道填充缺失日期(无法使用$densify)

解决MongoDB聚合显示日期范围内所有日期(含空任务日期)的方案

由于无法使用$densify,可以通过以下两种方式实现需求:

方案一:MongoDB 4.4+ 版本使用$documents + $lookup

利用$documents注入目标日期范围的所有日期,再通过左连接关联原任务数据,确保无任务日期保留空数组。

代码实现

const startDate = new Date("2022-10-19");
const endDate = new Date("2022-10-26");

// 生成日期范围内的所有日期(统一时间部分为00:00:00,匹配数据库date字段格式)
const allDates = [];
let currentDate = new Date(startDate);
while (currentDate <= endDate) {
  const dateOnly = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate());
  allDates.push({ date: dateOnly });
  currentDate.setDate(currentDate.getDate() + 1);
}

const pipeline = [
  // 注入所有日期作为初始文档
  { $documents: allDates },
  // 左连接原集合中对应日期的任务
  {
    $lookup: {
      from: "scheduleTasks", // 替换为你的集合实际名称
      let: { targetDate: "$date" },
      pipeline: [
        {
          $match: {
            $expr: {
              $and: [
                { $eq: ["$date", "$$targetDate"] },
                { $gte: ["$date", startDate] },
                { $lte: ["$date", endDate] }
              ]
            }
          }
        }
      ],
      as: "tasks"
    }
  },
  // 格式化结果结构,与原管道输出保持一致
  {
    $project: {
      _id: "$date",
      tasks: 1
    }
  },
  // 按日期倒序排序
  { $sort: { _id: -1 } }
];

const aggregationData = await ScheduleTaskModel.aggregate(pipeline);

说明

  • $documents会将生成的日期数组作为聚合的初始数据源
  • $lookup使用左连接,确保每个日期都保留,无匹配任务时tasks自动为空数组
  • 需保证生成的日期与数据库中date字段的时间格式一致,避免匹配失败

方案二:低版本MongoDB 代码层面合并结果

如果你的MongoDB版本低于4.4,无法使用$documents,可以在服务端代码中生成日期范围,再与原聚合结果合并。

代码实现

// 生成日期范围的工具函数
function generateDateRange(startDateStr, endDateStr) {
  const dates = [];
  const start = new Date(startDateStr);
  const end = new Date(endDateStr);
  
  let current = new Date(start);
  while (current <= end) {
    // 统一时间部分为00:00:00
    const dateOnly = new Date(current.getFullYear(), current.getMonth(), current.getDate());
    dates.push(dateOnly);
    current.setDate(current.getDate() + 1);
  }
  return dates;
}

// 原聚合管道:获取有任务的日期数据
const originalPipeline = [
  {
    $match: {
      date: { $gte: new Date("2022-10-19"), $lte: new Date("2022-10-26") },
    },
  },
  {
    $group: {
      _id: "$date",
      tasks: { $push: "$$ROOT" },
    },
  }
];

// 获取原聚合结果
const originalData = await ScheduleTaskModel.aggregate(originalPipeline);

// 生成目标日期范围内的所有日期
const allDates = generateDateRange("2022-10-19", "2022-10-26");

// 将原数据转为Map,快速查找对应日期的任务
const dateDataMap = new Map();
originalData.forEach(item => {
  const dateKey = item._id.toISOString();
  dateDataMap.set(dateKey, item);
});

// 合并结果,确保所有日期都存在
const aggregationData = allDates.map(date => {
  const dateKey = date.toISOString();
  const existingItem = dateDataMap.get(dateKey);
  return existingItem ? existingItem : { _id: date, tasks: [] };
}).sort((a, b) => b._id - a._id); // 按日期倒序排序

说明

  • 先通过原聚合获取有任务的日期数据,再在代码中补全缺失的日期
  • 使用Map存储原数据,提升查找效率
  • 最后排序保持与原管道一致的倒序逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 00:41:39