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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 12:24:46