进入MongoDB中文手册(4.2版本)目录
对于MongoDB中的许多用例,将相关数据存储在单个文档中的非规范化数据模型将是最佳的。但是,在某些情况下,将相关信息存储在单独的文档中(通常存储在不同的集合或数据库中)是有意义的。
重要
MongoDB 3.2引入了$lookup管道阶段,以对同一数据库中的未分片集合执行左外部联接。有关更多信息和示例,请参见$lookup。
从MongoDB 3.4开始,您还可以使用$graphLookup 管道阶段来加入未分片的集合以执行递归搜索。有关更多信息和示例,请参见 $graphLookup。
本页面概述了在$lookup和$graphLookup管道阶段之前的替代程序。
MongoDB应用程序使用以下两种方法之一来关联文档:
- 手动引用,您可以将一个文档的_id字段保存在另一文档中作为引用。然后,您的应用程序可以运行第二个查询从而返回相关数据。这些引用对于大多数用例而言都是简单且足够的。
- 数据库引用(DBRef),使用第一个文档的_id字段,集合名称以及(可选)其数据库名称的值来表示从一个文档到另一个文档的引用。通过包含这些名称,数据库引用可以使位于多个集合中的文档更易于与单个集合中的文档链接。
若要解析数据库引用,您的应用程序必须执行其他查询从而返回引用的文档。许多驱动程序都有帮助器方法,这些方法会自动形成对数据库引用的查询。驱动程序不会自动将数据库引用解析为文档。
数据库引用提供了一种通用的格式和类型来表示文档之间的关系。如果数据库必须与多个框架和工具进行交互,则数据库引用格式还提供了表示文档之间链接的通用语义。
除非您有令人信服的理由使用数据库引用,否则请改为使用手动引用。
1 手动引用
1.1 背景
使用手动引用是一种将一个文档的 _id字段包含在另一文档中的做法 。然后,应用程序可以根据需要发出第二个查询来解析引用的字段。
1.2 程序
考虑以下操作,使用第一个文档的_id字段作为第二个文档的引用来插入两个 文档:
original_id = ObjectId()
db.places.insert({
"_id": original_id,
"name": "Broadway Center",
"url": "bc.example.net"
})
db.people.insert({
"name": "Erin",
"places_id": original_id,
"url": "bc.example.net/Erin"
})
然后,当查询从people集合中返回文档时,您可以根据需要再次查询places集合中places_id字段所引用的文档。
1.3 使用
对于您希望在两个文档之间存储关系的几乎每种情况,请使用手动引用。引用很容易创建,您的应用程序可以根据需要解析引用。
手动链接的唯一限制是这些引用不传达数据库和集合名称。如果单个集合中的文档与多个集合中的文档相关,则可能需要考虑使用数据库引用。
2 数据库引用(DBRef)
2.1 背景
数据库引用是表示一个文档的约定(convention),而不是特定的引用类型。除了_id字段的值外,它们还包括集合的名称,在某些情况下还包括数据库的名称。
2.2 格式
DBRef具有以下字段:
- $ref
$ref字段保存引用文档所在的集合的名称。
- $id
$id字段包含引用文档中_id字段的值。
- $db
可选的。
包含引用文档所在的数据库的名称。
仅某些驱动程序支持$db引用参数。
示例
DBRef文档类似于以下文档:
{ "$ref" : <value>, "$id" : <value>, "$db" : <value> }
考虑来自在集合中的creator字段存储数据库引用的文档 :
{
"_id" : ObjectId("5126bbf64aed4daf9e2ab771"),
// .. application fields
"creator" : {
"$ref" : "creators",
"$id" : ObjectId("5126bc054aed4daf9e2ab772"),
"$db" : "users"
}
}
此示例中的数据库引用指向: users数据库, creators 集合中, _id字段值为ObjectId(“5126bc054aed4daf9e2ab772”)的文档。
注意
数据库引用中字段的顺序很重要,使用DBRef时必须使用上述顺序。
2.3 支持数据库引用的驱动程序
2.4 使用
在大多数情况下,您应该使用手动引用方法来连接两个或更多相关文档。但是,如果需要引用多个集合中的文档,请考虑使用数据库引用。
进入MongoDB中文手册(4.2版本)目录