如何使用MongoDB聚合框架基于现有集合过滤含指定ID数组的对象
可以通过MongoDB聚合管道实现该需求,完整实现方案如下:
你需要先把originTimeStamp和controlIds作为聚合参数传入,同时注意所有时间字段统一转为ISODate类型避免比较出错。
db.activityLogs.aggregate([ // 第一步:过滤出日志中controlId属于给定controlIds的所有记录 { $match: { controlId: { $in: Object.values(controlIds).flat() } } }, // 第二步:按controlId分组,取每个id对应的最新createdAt时间 { $group: { _id: "$controlId", maxCreatedAt: { $max: "$createdAt" } } }, // 第三步:归集所有需要删除的controlId,关联对应分类的origin时间判断 { $group: { _id: null, toRemove: { $push: { $cond: [ // 判断当前id所属分类的origin时间是否小于日志中的时间 { $or: [ { $and: [{ $in: ["$_id", controlIds.chats] }, { $lt: [ISODate(originTimeStamp.chats), "$maxCreatedAt"] }] }, { $and: [{ $in: ["$_id", controlIds.users] }, { $lt: [ISODate(originTimeStamp.users), "$maxCreatedAt"] }] }, { $and: [{ $in: ["$_id", controlIds.history] }, { $lt: [ISODate(originTimeStamp.history), "$maxCreatedAt"] }] } ] }, "$_id", "$$REMOVE" // 不符合删除条件的id不加入待删除列表 ] } } } }, // 第四步:生成最终过滤后的controlIds对象 { $project: { _id: 0, chats: { $filter: { input: controlIds.chats, cond: { $not: { $in: ["$$this", "$toRemove"] } } } }, users: { $filter: { input: controlIds.users, cond: { $not: { $in: ["$$this", "$toRemove"] } } } }, history: { $filter: { input: controlIds.history, cond: { $not: { $in: ["$$this", "$toRemove"] } } } } } } ])
执行逻辑说明:
- 首先筛选日志范围,排除无关的controlId记录,减少后续计算量
- 每个controlId只需要保留最新的一条活动时间做判断,避免重复计算
- 待删除id归集完成后,直接对原controlIds的每个分类数组做过滤,排除待删除id即可得到最终结果
你之前的尝试没有生效的原因是没有在聚合中关联分类和对应origin时间的判断逻辑,仅拉取了符合条件的id列表,需要额外的代码做过滤,上述方案可以直接返回你需要的最终controlIds结构。
内容的提问来源于stack exchange,提问作者Ashish Bairwa
相关产品推荐
相关产品推荐

