19

所以这里是问题:

我在集合 A 中有文档,当它首次创建时,它没有被任何其他文档引用。在某个时候,集合 B 中的一个文档将被创建,它将引用集合 A 中文档的 ObjectId。

什么是查找集合 A 中未由集合 B 中的 I 文档引用的所有文档的最佳方法?

我了解 MongoDB 不支持连接,但我想知道除了从集合 B 获取所有引用的 ObjectId 并在集合 A 中查找不在该列表中的文档之外,是否有解决此问题的方法,因为此解决方案可能不会规模化。

我可以将集合 A 中的文档嵌入到集合 B 中的文档中,然后将其从集合 A 中删除吗?这是最好的解决方案吗?

感谢您的帮助和评论。

4

3 回答 3

18

在 MongoDB 3.2 中,添加$lookup运算符使这成为可能:

db.a.aggregate(
[
    {
        $lookup: {
            from: "b", <-- secondary collection name containing references to _id of 'a'
            localField: "_id",  <-- the _id field of the 'a' collection
            foreignField: "a_id", <-- the referencing field of the 'b' collection
            as: "references"
        }
    },
    {
        $match: {
            references: []
        }
    }
]);

上面的查询将返回 collectiona中没有在 collection 中引用的所有文档b

不过要小心。性能可能会成为大型集合的问题。


于 2016-09-18T09:01:09.440 回答
5

很多选择:

1)将B文档的id添加到A文档中的一个数组中(反向引用)。现在您可以查找在该数组中没有任何元素的 A 文档。问题:如果您有很多交叉引用,数组可能会变得太大而无法满足文档大小。

2) 添加一个集合 C 来跟踪 A 和 B 之间的引用。表现得像一个连接表。

3)在“引用”中有一个简单的标志。当您添加 B 时,将它引用的所有 A 标记为“已引用”。当您删除 B 时,请扫描 B 以查找它所引用的所有 A,并取消标记任何不再具有引用的 A。问题:可能会不同步。

4) 在 B 上使用 map reduce 来创建一个集合,其中包含任何 B 引用的所有 A 的 id。使用该集合标记所有被引用的 A(在首先取消所有标记之后)。可以使用它定期修复 (3)。

5) 将两种文档类型放在同一个集合中,并使用 map reduce 发出 _id 和一个标志来表示“在 A 中”或“被 B 引用”。在减少步骤中,查找具有“在 A 中”但不是“被 B 引用”的任何组。

...

于 2012-05-23T04:30:07.420 回答
0

由于没有连接,唯一的选择是您提到的一次:要么使用嵌入式文档,要么让自己使用两部分查询。

这取决于您的实现,但将文档类型 B 添加到 A 中的相应文档听起来是最好的选择。这样,您可以使用简单的查询($exists 运算符)检索没有 B 的 A ...

A.find( { B: { $exists: false } })
于 2012-05-23T03:51:46.993 回答