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

MongoDB中如何通过日期数组筛选指定数据?

MongoDB聚合查询中日期数组筛选返回空结果的修正方案

问题场景

MongoDB文档包含scheduleStartDate字段,先通过范围筛选数据:

$match: {
  jobId: { $in: value.jobIds },
  scheduleStartDate: { $gte: startDate, $lte: endDate },
}

后续需要通过API传入的日期数组(示例:["11-03-2021","12-03-2021",...])进一步过滤,但添加的逻辑返回空结果:

if (value.dates) {
  value.dates = value.dates.map((date) => {
    return moment(date, "DD/MM/YYYY").format("YYYY-MM-DD[T]HH:mm:ss");
  });
  filterArray.push({
    $match: {
      $and: {scheduleStartDate: value.dates},
    },
  });
}

完整聚合代码如下:

const result = await slotModel.aggregate([
  {
    $match: {
      userId: { $in: value.userIds },
      scheduleStartDate: { $gte: startDate, $lte: endDate },
    },
  },
  {
    $lookup: {
      from: "myjobs",
      localField: "jobId",
      foreignField: "_id",
      as: "job",
    },
  },
  {
    $match: {
      $and: filterArray,
    },
  },
  {
    $project: {
      round: 1,
      type: 1,
      mode: 1,
      scheduleStartDate: 1,
      scheduleEndDate: 1,
      feedbackId: 1,
    },
  },
]);

return result;

问题根源

  1. 日期解析格式错误:API传入的日期用-分隔(如11-03-2021),但代码中用DD/MM/YYYY解析,导致生成的日期完全错误。
  2. $match条件结构错误:将$match阶段对象推入filterArray,再用$and包裹,导致聚合条件格式不符合MongoDB要求;同时错误地直接将数组赋值给scheduleStartDate,未使用$in操作符。
  3. 日期精度不匹配:原文档scheduleStartDate含时分秒,转换后的日期默认是当天零点,若原数据时间不是零点则无法匹配。

修正方案

方案1:精确匹配日期(含时分秒)

如果需要严格匹配scheduleStartDate等于指定日期的零点时刻,修正代码如下:

// 构建filterArray的逻辑
if (value.dates) {
  // 注意传入日期是DD-MM-YYYY格式,用对应格式解析
  const targetDates = value.dates.map(date => 
    moment(date, "DD-MM-YYYY").startOf('day').toDate()
  );
  // 直接推入匹配条件,而非$match阶段
  filterArray.push({
    scheduleStartDate: { $in: targetDates }
  });
}

// 聚合查询保持原结构,注意filterArray里是条件对象,不是$match阶段
const result = await slotModel.aggregate([
  {
    $match: {
      userId: { $in: value.userIds },
      scheduleStartDate: { $gte: startDate, $lte: endDate },
    },
  },
  {
    $lookup: {
      from: "myjobs",
      localField: "jobId",
      foreignField: "_id",
      as: "job",
    },
  },
  // 直接用$match包裹filterArray,无需额外$and(MongoDB默认逻辑与)
  { $match: { $and: filterArray } },
  {
    $project: {
      round: 1,
      type: 1,
      mode: 1,
      scheduleStartDate: 1,
      scheduleEndDate: 1,
      feedbackId: 1,
    },
  },
]);

方案2:匹配日期部分(忽略时分秒)

如果只需匹配日期,不管具体时分秒,推荐用$dateTrunc截断日期到天再匹配:

const pipeline = [
  {
    $match: {
      userId: { $in: value.userIds },
      scheduleStartDate: { $gte: startDate, $lte: endDate },
    },
  },
  {
    $lookup: {
      from: "myjobs",
      localField: "jobId",
      foreignField: "_id",
      as: "job",
    },
  }
];

if (value.dates) {
  // 转换为YYYY-MM-DD格式的字符串数组
  const targetDateStrs = value.dates.map(date => 
    moment(date, "DD-MM-YYYY").format("YYYY-MM-DD")
  );
  // 添加字段存储截断后的日期
  pipeline.push({
    $addFields: {
      scheduleDate: { $dateTrunc: { date: "$scheduleStartDate", unit: "day" } }
    }
  });
  // 匹配日期字符串
  pipeline.push({
    $match: {
      $expr: {
        $in: [
          { $dateToString: { format: "%Y-%m-%d", date: "$scheduleDate" } },
          targetDateStrs
        ]
      }
    }
  });
}

// 添加投影阶段,移除临时字段
pipeline.push({
  $project: {
    round: 1,
    type: 1,
    mode: 1,
    scheduleStartDate: 1,
    scheduleEndDate: 1,
    feedbackId: 1,
    scheduleDate: 0
  }
});

const result = await slotModel.aggregate(pipeline);

关键注意事项

  • 务必确保日期解析格式与传入格式一致:API用DD-MM-YYYY,则moment解析时必须用对应格式,否则会生成错误日期。
  • 不要将$match阶段对象推入filterArray,应直接推入条件键值对,避免聚合结构错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 03:15:52