如何编写MongoDB聚合管道生成foreignKey-布尔值键值对?
解决MongoDB聚合查询:按指定foreignKey生成存在性布尔值对象
需求回顾
给定一组字符串化的foreignKey ObjectId,生成键为foreignKey、值为布尔值的对象:若该foreignKey在最近x天内有文档(计数>0)则为true,否则为false。
实现步骤与聚合查询
假设集合名为yourCollection,给定的foreignKeys数组为["6001","6002","6003"],x=2天,先完成预处理再执行聚合管道:
// 预处理:转换字符串为ObjectId,计算时间边界 const foreignKeys = ["6001","6002","6003"].map(id => ObjectId(id)); const days = 2; const timeThreshold = new Date(Date.now() - days * 24 * 60 * 60 * 1000); // 聚合查询 db.yourCollection.aggregate([ // 筛选最近x天内、foreignKey在目标数组中的文档 { $match: { foreignKey: { $in: foreignKeys }, createdAt: { $gte: timeThreshold } } }, // 按foreignKey分组,标记是否存在文档(只要有1个就为true) { $group: { _id: "$foreignKey", exists: { $first: true } } }, // 转换为{key: 字符串ID, value: 布尔值}格式 { $project: { _id: 0, key: { $toString: "$_id" }, value: "$exists" } }, // 收集已存在的key,同时生成包含所有目标key的默认值数组 { $group: { _id: null, existingKeys: { $push: { k: "$key", v: "$value" } }, allKeys: { $first: foreignKeys.map(id => ({ k: id.toString(), v: false })) } } }, // 合并默认值与实际存在的key结果 { $project: { combined: { $mergeObjects: [ { $arrayToObject: "$allKeys" }, { $arrayToObject: "$existingKeys" } ] } } }, // 输出最终对象 { $replaceRoot: { newRoot: "$combined" } } ]);
代码解释
- 预处理:把字符串ID转为MongoDB原生
ObjectId,同时计算最近x天的时间阈值,减少聚合管道内的重复计算。 - $match阶段:快速筛选符合条件的文档,缩小后续处理的数据范围。
- 第一次$group:按
foreignKey分组,用$first: true标记存在性,比统计总数更高效。 - $project阶段:将分组结果转为便于转成对象的键值对格式。
- 第二次$group:收集所有存在的key,同时生成包含全部目标key、默认值为
false的数组。 - $mergeObjects + $arrayToObject:合并默认值对象与实际存在的key结果,存在的key会覆盖默认的
false。 - $replaceRoot:将合并后的对象作为最终输出的根文档。
示例输出
对应题目示例场景,执行后输出:
{ "6001": true, "6002": true, "6003": false }
注意事项
- 建议为
foreignKey和createdAt字段建立复合索引,提升查询效率:db.yourCollection.createIndex({ foreignKey: 1, createdAt: -1 }); - 若判断逻辑基于
updatedAt,只需将$match中的createdAt替换为updatedAt即可。
内容的提问来源于stack exchange,提问作者user16554884
相关产品推荐
相关产品推荐

