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

MongoDB中如何校验对象内元素日期与同对象参考元素日期的关系

MongoDB聚合查询:筛选与参考日期相差1年以内的数组元素

需求说明

校验文档内items数组的所有元素,以数组中第一个元素的日期为参考标准,保留与该参考日期相差1年以内的元素,移除超出范围的元素。

示例数据

[
  {
    "_id": "102",
    "items": [
      {
        "p_id": "102",
        "e_date": "2017-04-01T00:00:00.000",
        "h_val": 4
      },
      {
        "p_id1": "102",
        "e_date1": "2004-05-01T00:00:00.000",
        "s_val": 87,
        "d_val": 58
      },
      {
        "p_id1": "102",
        "e_date1": "2016-09-01T00:00:00.000",
        "s_val": 81,
        "d_val": 62
      }
    ],
    "count": 3
  }
]

示例结果要求:文档_id:102中,保留第一个元素(参考日期本身)和第三个元素(与参考日期2017-04-01相差约7个月,在1年以内),移除第二个元素(相差超过12年)。

原查询的问题

你提供的聚合查询逻辑存在错误:

  • 错误地在单个元素内对比e_date和e_date1,但实际需求是所有元素与第一个元素的e_date做对比;
  • 用固定400天作为阈值,不符合“1年以内”的准确要求;
  • 未处理元素日期字段名不一致的情况(有的是e_date,有的是e_date1)。

正确的聚合查询方案

db.collection.aggregate([
  {
    $addFields: {
      // 提取参考日期:items数组第一个元素的e_date并转为日期类型
      "referenceDate": {
        $dateFromString: {
          dateString: { $arrayElemAt: ["$items.e_date", 0] }
        }
      }
    }
  },
  {
    $project: {
      _id: 1,
      count: 1,
      "items": {
        $filter: {
          input: "$items",
          as: "item",
          cond: {
            // 计算当前元素日期与参考日期的绝对毫秒差,判断是否≤1年的毫秒数
            $lte: [
              { $abs: {
                  $subtract: [
                    // 处理元素的日期字段:优先取e_date,没有则取e_date1,转为日期类型
                    { $dateFromString: {
                        dateString: { $ifNull: ["$$item.e_date", "$$item.e_date1"] }
                      }
                    },
                    "$referenceDate"
                  ]
                }
              },
              // 1年的毫秒数:365天×24小时×60分钟×60秒×1000毫秒
              31536000000
            ]
          }
        }
      }
    }
  },
  // 可选:移除临时的referenceDate字段
  { $unset: "referenceDate" }
])

查询解释

  1. $addFields阶段:提取items数组第一个元素的e_date,转换为MongoDB日期类型,存储为临时字段referenceDate,作为后续对比的参考标准;
  2. $project阶段:使用$filter遍历items数组:
    • 对每个元素,用$ifNull兼容e_date和e_date1两种字段名,将其转为日期类型;
    • 计算该日期与referenceDate的毫秒差绝对值,判断是否小于等于1年的毫秒数(31536000000),满足条件的元素保留;
  3. $unset阶段:移除临时的referenceDate字段,保持文档结构整洁。

如果需要更精确的“1年”(考虑闰年),可以用$dateAdd计算参考日期加1年后的日期,再判断当前元素日期是否在[referenceDate, referenceDate+1年]区间内,调整后的条件如下:

cond: {
  $and: [
    { $gte: [
        { $dateFromString: { dateString: { $ifNull: ["$$item.e_date", "$$item.e_date1"] } } },
        "$referenceDate"
      ]
    },
    { $lte: [
        { $dateFromString: { dateString: { $ifNull: ["$$item.e_date", "$$item.e_date1"] } } },
        { $dateAdd: { startDate: "$referenceDate", unit: "year", amount: 1 } }
      ]
    }
  ]
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 23:25:16