MongoDB聚合过滤关联文档:移除被引用的目标文档
问题:移除Mongoose聚合结果中被引用的文档
我在Mongoose中实现聚合操作时遇到了问题,当前得到的结果如下:
[ { _id: new ObjectId("630bb658370cc689973c5bb4"), isRead: true, user: new ObjectId("630273bbe0f3f82d85b149bd"), globalRef: new ObjectId("630bb649370cc689973c5b62"), }, { _id: new ObjectId("630bb649370cc689973c5b62"), isRead: false, }, { _id: new ObjectId("6306bcf16fa60080148fefb6"), isRead: false, }, { _id: new ObjectId("630273bbe0f3f82d85b149bd"), isRead: false, user: new ObjectId("630273bbe0f3f82d85b149bd") }, { _id: new ObjectId("6306bcf16fa60080148fefb7"), isRead: true, user: new ObjectId("630273bbe0f3f82d85b149bd") } ]
可以看到第一个文档的globalRef字段引用了第二个文档的_id,我希望移除那些被其他文档引用的文档,请问能否通过$match、$group、$project或$filter实现该需求?期望结果如下:
[ { _id: new ObjectId("630bb658370cc689973c5bb4"), isRead: true, user: new ObjectId("630273bbe0f3f82d85b149bd"), globalRef: new ObjectId("630bb649370cc689973c5b62"), }, { _id: new ObjectId("6306bcf16fa60080148fefb6"), isRead: false, }, { _id: new ObjectId("630273bbe0f3f82d85b149bd"), isRead: false, user: new ObjectId("630273bbe0f3f82d85b149bd") }, { _id: new ObjectId("6306bcf16fa60080148fefb7"), isRead: true, user: new ObjectId("630273bbe0f3f82d85b149bd") } ]
解决方案
完全可以通过聚合相关操作实现,核心思路是先收集所有被globalRef引用的_id,再过滤掉这些被引用的文档。这里提供两种实用实现方式:
方式一:纯聚合管道内完成
YourModel.aggregate([ // 收集所有被globalRef引用的ID,自动去重 { $group: { _id: null, referencedIds: { $addToSet: "$globalRef" } } }, // 关联当前集合的所有文档 { $lookup: { from: "your-collection-name", // 替换为你的集合实际名称 as: "allDocs" } }, // 展开文档数组 { $unwind: "$allDocs" }, // 过滤掉_id在referencedIds中的文档 { $match: { $expr: { $not: { $in: ["$allDocs._id", "$referencedIds"] } } } }, // 恢复原始文档结构 { $replaceRoot: { newRoot: "$allDocs" } } ])
方式二:分两步执行(性能更优)
先查询出所有被引用的ID列表,再直接过滤掉这些ID对应的文档:
// 第一步:获取所有被globalRef引用的ID(自动去重,仅保留存在globalRef的文档) const referencedIds = await YourModel.distinct("globalRef", { globalRef: { $exists: true } }); // 第二步:用查询或聚合过滤掉被引用的文档 // 普通查询方式 const result = await YourModel.find({ _id: { $nin: referencedIds } }); // 聚合方式(如果必须用聚合) const aggregateResult = await YourModel.aggregate([ { $match: { _id: { $nin: referencedIds } } } ]);
两种方式都能满足需求,方式二更高效,尤其是数据量较大时,避免了聚合内的关联操作开销。
内容的提问来源于stack exchange,提问作者Samuel Sitruk
相关产品推荐
相关产品推荐

