MongoDB:数组对象元素映射与日期条件匹配分组需求
MongoDB 实现跨数组对象的日期差配对分组
问题背景
需要对集合中文档的e_date数组对象与e_date_1数组对象进行年份差计算,当两个对象的日期年份差绝对值≥13时,将这对对象组合成新的数组元素,最终输出所有符合条件的配对结果,而非仅布尔值判断矩阵。
集合示例数据
[ { "_id": ObjectId("60d21b4667d0d8992e610c85"), "e_date": [ { "id": 1, "date": ISODate("2000-05-10") }, { "id": 2, "date": ISODate("2023-03-15") } ], "e_date_1": [ { "id": 101, "date": ISODate("1985-07-20") }, { "id": 102, "date": ISODate("2010-11-01") } ] } ]
现有代码的局限
当前使用嵌套$map仅能生成布尔判断矩阵,无法保留实际配对的对象信息:
db.collection.aggregate([ { $project: { pair_check: { $map: { input: "$e_date", as: "ed", in: { $map: { input: "$e_date_1", as: "ed1", in: { $gte: [ { $abs: { $subtract: [{ $year: "$$ed.date" }, { $year: "$$ed1.date" }] } }, 13 ] } } } } } } } ])
输出为布尔矩阵:
{ "_id": ObjectId("60d21b4667d0d8992e610c85"), "pair_check": [[true, false], [false, true]] }
解决方案:生成实际配对对象数组
可以通过两种方式实现,根据数据规模选择合适的方案:
方案1:使用$unwind+$group(适合数据量中等的场景)
通过展开两个数组,筛选符合条件的配对后重新分组:
db.collection.aggregate([ // 展开e_date数组 { $unwind: "$e_date" }, // 展开e_date_1数组 { $unwind: "$e_date_1" }, // 计算年份差并标记符合条件的配对 { $addFields: { is_valid: { $gte: [ { $abs: { $subtract: [{ $year: "$e_date.date" }, { $year: "$e_date_1.date" }] } }, 13 ] } } }, // 筛选出符合条件的配对 { $match: { is_valid: true } }, // 按原文档_id分组,收集所有有效配对 { $group: { _id: "$_id", valid_pairs: { $push: { e_date_obj: "$e_date", e_date_1_obj: "$e_date_1" } } } } ])
方案2:使用$reduce+$filter(适合避免文档展开的场景)
在$project阶段直接通过嵌套聚合操作生成配对数组,无需展开文档:
db.collection.aggregate([ { $project: { valid_pairs: { $reduce: { input: "$e_date", initialValue: [], in: { // 拼接当前e_date元素匹配到的所有e_date_1元素 $concatArrays: [ "$$value", { $map: { // 过滤出与当前e_date元素年份差≥13的e_date_1元素 input: { $filter: { input: "$e_date_1", as: "ed1", cond: { $gte: [ { $abs: { $subtract: [{ $year: "$$this.date" }, { $year: "$$ed1.date" }] } }, 13 ] } } }, as: "matched_ed1", // 生成配对对象 in: { e_date_obj: "$$this", e_date_1_obj: "$$matched_ed1" } } } ] } } } } } ])
期望输出
两种方案均会输出如下结构的结果:
{ "_id": ObjectId("60d21b4667d0d8992e610c85"), "valid_pairs": [ { "e_date_obj": { "id": 1, "date": ISODate("2000-05-10") }, "e_date_1_obj": { "id": 101, "date": ISODate("1985-07-20") } }, { "e_date_obj": { "id": 2, "date": ISODate("2023-03-15") }, "e_date_1_obj": { "id": 101, "date": ISODate("1985-07-20") } } ] }
内容的提问来源于stack exchange,提问作者Will Jue
相关产品推荐
相关产品推荐

