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

MongoDB聚合查询:筛选日期范围内子文档并保留原结构

保留原文档结构筛选MongoDB用户订阅记录的解决方案

我明白你的需求——你想要筛选出每个用户下符合日期条件的订阅记录,同时保持原有的文档结构(每个用户对应一个文档,包含筛选后的订阅数组),而不是把每条订阅拆成单独的文档。之前的$unwind会破坏原结构,$redact又因为类型问题报错,咱们来解决这个问题:

正确的聚合查询

直接用$filter来处理订阅数组,不需要拆分组装,就能完美保留原文档结构:

db.gyms.aggregate([
  {
    $addFields: {
      subscriptions: {
        $filter: {
          input: "$subscriptions",
          as: "sub",
          cond: {
            $and: [
              { $ne: ["$$sub.activation_date", null] }, // 避免空日期导致的类型错误
              { $eq: [{ $month: "$$sub.activation_date" }, 1] } // 筛选1月份的订阅
            ]
          }
        }
      }
    }
  },
  // 可选:如果要移除没有符合条件订阅的用户,加上这个阶段
  {
    $match: {
      "subscriptions.0": { $exists: true }
    }
  }
]).pretty()

为什么这个方法可行?

  1. 保留原结构:$addFields会直接替换原文档中的subscriptions字段为筛选后的数组,每个用户依然是一个独立的文档,完全符合你想要的输出格式。
  2. 避免类型错误:先通过$ne判断日期字段不为空,解决了你用$redact时遇到的“无法将missing类型转为Date”的报错——因为$redact会遍历文档的所有字段,包括非订阅相关的字段,而$filter只针对subscriptions数组内的元素处理。
  3. 更高效简洁:相比先用$unwind拆分再$group重组的方式,$filter一步到位,性能更好。

如果需要指定具体日期范围

比如要筛选2018年1月1日到1月31日的订阅,只需要修改cond里的判断条件:

db.gyms.aggregate([
  {
    $addFields: {
      subscriptions: {
        $filter: {
          input: "$subscriptions",
          as: "sub",
          cond: {
            $and: [
              { $ne: ["$$sub.activation_date", null] },
              { $gte: ["$$sub.activation_date", ISODate("2018-01-01T00:00:00Z")] },
              { $lt: ["$$sub.activation_date", ISODate("2018-02-01T00:00:00Z")] }
            ]
          }
        }
      }
    }
  },
  { $match: { "subscriptions.0": { $exists: true } } }
]).pretty()

运行这个查询后,你就能得到每个用户仅包含符合条件订阅记录的文档,完全匹配你期望的输出格式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:26:19