进入MongoDB中文手册(4.2版本)目录
1 概述
此页面描述了一种数据模型,该数据模型使用嵌入式文档来描述所连接数据之间的一对一关系。将连接的数据嵌入单个文档中可以减少获取数据所需的读取操作次数。通常,您应该对模式(schema)进行结构设计,以便您的应用程序可以在一次读取操作中接收其所有必需的信息。
2 嵌入式文档模式(Pattern)
考虑以下映射patron和 address关系的示例。该示例说明了如果您需要在另一个实体的上下文中查看一个数据实体,则与引用相比,嵌入的优势。在patron和 address数据之间的一对一关系中,address属于patron。
在规范化数据模型中,address文档包含对patron文档的引用。
// patron document
{
_id: "joe",
name: "Joe Bookreader"
}
// address document
{
patron_id: "joe", // reference to patron document
street: "123 Fake Street",
city: "Faketon",
state: "MA",
zip: "12345"
}
如果经常使用name信息检索address数据,然后使用引用,则您的应用程序需要发出多个查询来解析引用。更好的数据模型是将address数据嵌入patron数据中,如以下文档所示:
{
_id: "joe",
name: "Joe Bookreader",
address: {
street: "123 Fake Street",
city: "Faketon",
state: "MA",
zip: "12345"
}
}
使用嵌入式数据模型,您的应用程序可以通过一个查询来检索完整的patron信息。
3 子集模式(Pattern)
嵌入式文档模式(Pattern)的潜在问题是,它可能导致产生包含应用程序不需要的字段的大型文档。这些不必要的数据可能会导致服务器上的额外负载并减慢读取操作的速度。相反,您可以使用子集模式来检索在单个数据库调用中最常访问的数据子集。
考虑一个显示电影信息的应用程序。该数据库包含具有以下模式(schema)的movie集合:
{
"_id": 1,
"title": "The Arrival of a Train",
"year": 1896,
"runtime": 1,
"released": ISODate("01-25-1896"),
"poster": "http://ia.media-imdb.com/images/M/MV5BMjEyNDk5MDYzOV5BMl5BanBnXkFtZTgwNjIxMTEwMzE@._V1_SX300.jpg",
"plot": "A group of people are standing in a straight line along the platform of a railway station, waiting for a train, which is seen coming at some distance. When the train stops at the platform, ...",
"fullplot": "A group of people are standing in a straight line along the platform of a railway station, waiting for a train, which is seen coming at some distance. When the train stops at the platform, the line dissolves. The doors of the railway-cars open, and people on the platform help passengers to get off.",
"lastupdated": ISODate("2015-08-15T10:06:53"),
"type": "movie",
"directors": [ "Auguste Lumière", "Louis Lumière" ],
"imdb": {
"rating": 7.3,
"votes": 5043,
"id": 12
},
"countries": [ "France" ],
"genres": [ "Documentary", "Short" ],
"tomatoes": {
"viewer": {
"rating": 3.7,
"numReviews": 59
},
"lastUpdated": ISODate("2020-01-09T00:02:53")
}
}
当前,movie集合包含应用程序不需要显示电影的简单概述的几个字段,例如 fullplot和rating信息。可以将所有电影数据分为两个集合,而不是将所有电影数据存储在一个集合中:
- movie集合包含有关电影的基本信息。这是应用程序默认加载的数据:
// movie collection { "_id": 1, "title": "The Arrival of a Train", "year": 1896, "runtime": 1, "released": ISODate("1896-01-25"), "type": "movie", "directors": [ "Auguste Lumière", "Louis Lumière" ], "countries": [ "France" ], "genres": [ "Documentary", "Short" ], }
- movie_details集合包含每个电影的其他较少访问的数据:
// movie_details collection { "_id": 156, "movie_id": 1, // reference to the movie collection "poster": "http://ia.media-imdb.com/images/M/MV5BMjEyNDk5MDYzOV5BMl5BanBnXkFtZTgwNjIxMTEwMzE@._V1_SX300.jpg", "plot": "A group of people are standing in a straight line along the platform of a railway station, waiting for a train, which is seen coming at some distance. When the train stops at the platform, ...", "fullplot": "A group of people are standing in a straight line along the platform of a railway station, waiting for a train, which is seen coming at some distance. When the train stops at the platform, the line dissolves. The doors of the railway-cars open, and people on the platform help passengers to get off.", "lastupdated": ISODate("2015-08-15T10:06:53"), "imdb": { "rating": 7.3, "votes": 5043, "id": 12 }, "tomatoes": { "viewer": { "rating": 3.7, "numReviews": 59 }, "lastUpdated": ISODate("2020-01-29T00:02:53") } }
此方法提高了读取性能,因为它要求应用程序读取较少的数据来满足其最常见的请求。如果需要,应用程序可以进行额外的数据库调用来获取访问频率较低的数据。
提示
在考虑将数据拆分到哪里时,数据中最常访问的部分应该放在应用程序首先加载的集合中。
也可以看看:
- 要了解如何使用子集模式对集合之间的一对多关系进行建模,请参阅使用嵌入式文档的一对多关系模型。
3.1 子集模式的权衡
使用包含更频繁访问的数据的较小文档可以减小工作集的整体大小。这些较小的文档可提高读取性能,并为应用程序提供更多内存。
但是,了解您的应用程序及其加载数据的方式很重要。如果将数据不正确地拆分为多个集合,则应用程序通常将需要多次访问数据库,并依赖于连接(JOIN)操作来检索其所需的所有数据。
此外,将数据分为多个小集合可能会增加所需的数据库维护,因为可能很难跟踪哪些数据存储在哪个集合中。
进入MongoDB中文手册(4.2版本)目录