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

如何让Mongoose聚合查询返回含无预订日期(count为0)的结果?

解决Mongoose聚合查询中补全无预订日期的问题

原聚合查询仅返回存在预订记录的日期,要补全无预订日期的count:0条目,核心思路是先生成目标日期区间的完整日期序列,再与统计结果关联。以下是两种可行方案:

方案一:聚合管道内生成日期序列并关联

直接在MongoDB聚合管道中生成完整日期范围,通过左连接关联原统计数据,自动补全无数据日期的count值:

const startDate = new Date("2022-09-04");
const endDate = new Date("2022-09-10");
// 计算日期区间的总天数(包含起止日)
const daysDiff = Math.ceil((endDate - startDate) / (1000 * 60 * 60 * 24));

const bookings = await Bookings.aggregate([
  // 创建空文档用于生成日期序列
  { $documents: [{}] },
  // 生成0到总天数的数字偏移量数组
  {
    $addFields: {
      dayOffsets: { $range: [0, daysDiff + 1] }
    }
  },
  // 拆分偏移量数组为单个文档
  { $unwind: "$dayOffsets" },
  // 根据偏移量生成目标日期
  {
    $addFields: {
      targetDate: {
        $dateFromParts: {
          year: { $year: startDate },
          month: { $month: startDate },
          day: { $add: [{ $dayOfMonth: startDate }, "$dayOffsets"] }
        }
      }
    }
  },
  // 左连接原集合的预订统计数据
  {
    $lookup: {
      from: "bookings", // 注意这里填写集合的实际名称(不是模型名)
      let: { targetDate: "$targetDate" },
      pipeline: [
        {
          $match: {
            $expr: {
              $and: [
                { $eq: ["$bookingDate", "$$targetDate"] },
                { $in: ["$store", storeIds] }
              ]
            }
          }
        },
        { $count: "count" }
      ],
      as: "bookingData"
    }
  },
  // 处理count字段:有数据取统计值,无数据设为0
  {
    $addFields: {
      count: {
        $cond: {
          if: { $gt: [{ $size: "$bookingData" }, 0] },
          then: { $arrayElemAt: ["$bookingData.count", 0] },
          else: 0
        }
      },
      _id: "$targetDate"
    }
  },
  // 保留需要的字段
  {
    $project: {
      _id: 1,
      count: 1
    }
  },
  // 按日期排序
  { $sort: { _id: 1 } }
]);

方案二:聚合后用JavaScript补全日期

先执行原聚合查询拿到已有数据,再通过JS生成完整日期序列并填充缺失值,逻辑更直观易维护:

const startDate = new Date("2022-09-04");
const endDate = new Date("2022-09-10");

// 1. 执行原聚合查询获取有预订记录的日期统计
const existingBookings = await Bookings.aggregate([
  {
    $match: {
      store: { $in: storeIds },
      bookingDate: { $gte: startDate, $lte: endDate }
    }
  },
  {
    $group: {
      _id: "$bookingDate",
      count: { $sum: 1 }
    }
  },
  { $sort: { _id: 1 } }
]);

// 2. 生成目标区间的完整日期映射表,默认count为0
const dateMap = new Map();
const currentDate = new Date(startDate);
while (currentDate <= endDate) {
  const dateISO = currentDate.toISOString();
  dateMap.set(dateISO, { _id: dateISO, count: 0 });
  currentDate.setDate(currentDate.getDate() + 1);
}

// 3. 将已有统计数据填充到映射表中
existingBookings.forEach(item => {
  const dateISO = item._id.toISOString();
  if (dateMap.has(dateISO)) {
    dateMap.set(dateISO, item);
  }
});

// 4. 转换为最终结果数组
const bookings = Array.from(dateMap.values());

方案对比

  • 聚合管道方案:所有逻辑在数据库端完成,适合需要直接返回完整结果的场景,无需额外JS处理。
  • JavaScript补全方案:代码更简洁易懂,调试方便,适合日期区间较短的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:39:26