使用嵌入式文档建立一对多关系模型
Overview
本页描述的数据模型使用嵌入式文档描述连接数据之间的一对多关系。 在单个文档中嵌入连接的数据可以减少获取数据所需的读取操作次数。 一般来说,您应该构建模式,以便应用程序在单个读取操作中接收所需的所有信息。
嵌入式文档模式
请考虑以下映射客户和多个地址关系的示例。 该示例说明了如果您需要在另一个数据实体的上下文中查看多个数据实体,则嵌入相对于引用的优势。 在 patron
和address
数据之间的这种一对多关系中, patron
具有多个address
实体。
在规范化Realm 数据模型中, address
文档包含对patron
文档的引用。
// patron document { _id: "joe", name: "Joe Bookreader" } // address documents { patron_id: "joe", // reference to patron document street: "123 Fake Street", city: "Faketon", state: "MA", zip: "12345" } { patron_id: "joe", street: "1 Some Other Street", city: "Boston", state: "MA", zip: "12345" }
如果您的应用程序经常检索带有name
信息的address
数据,则您的应用程序需要发出多个查询来解析引用。 更优化的模式是将address
数据实体嵌入到patron
数据中,如以下文档所示:
{ "_id": "joe", "name": "Joe Bookreader", "addresses": [ { "street": "123 Fake Street", "city": "Faketon", "state": "MA", "zip": "12345" }, { "street": "1 Some Other Street", "city": "Boston", "state": "MA", "zip": "12345" } ] }
借助嵌入式数据模型,应用程序可以通过一次查询检索完整的客户信息。
子集模式
嵌入式文档模式的一个潜在问题是,它可能导致文档过大,尤其是在嵌入式字段没有限制的情况下。 在这种情况下,您可以使用子集模式仅访问权限应用程序所需的数据,而不是访问整个嵌入数据设立。
考虑一个包含产品评论列表的电商站点:
{ "_id": 1, "name": "Super Widget", "description": "This is the most useful item in your toolbox.", "price": { "value": NumberDecimal("119.99"), "currency": "USD" }, "reviews": [ { "review_id": 786, "review_author": "Kristina", "review_text": "This is indeed an amazing widget.", "published_date": ISODate("2019-02-18") }, { "review_id": 785, "review_author": "Trina", "review_text": "Nice product. Slow shipping.", "published_date": ISODate("2019-02-17") }, ... { "review_id": 1, "review_author": "Hans", "review_text": "Meh, it's okay.", "published_date": ISODate("2017-12-06") } ] }
评论按时间倒序排列。用户访问产品页面时,应用程序会加载最近十条评论。
您可以将该集合拆分为两个集合,而不存储该产品的所有评论:
product
collection 存储每个产品的信息,包括该产品的 10 条最新评论:{ "_id": 1, "name": "Super Widget", "description": "This is the most useful item in your toolbox.", "price": { "value": NumberDecimal("119.99"), "currency": "USD" }, "reviews": [ { "review_id": 786, "review_author": "Kristina", "review_text": "This is indeed an amazing widget.", "published_date": ISODate("2019-02-18") } ... { "review_id": 777, "review_author": "Pablo", "review_text": "Amazing!", "published_date": ISODate("2019-02-16") } ] } review
collection 存储所有评论。每条评论都包含对相应产品的引用。{ "review_id": 786, "product_id": 1, "review_author": "Kristina", "review_text": "This is indeed an amazing widget.", "published_date": ISODate("2019-02-18") } { "review_id": 785, "product_id": 1, "review_author": "Trina", "review_text": "Nice product. Slow shipping.", "published_date": ISODate("2019-02-17") } ... { "review_id": 1, "product_id": 1, "review_author": "Hans", "review_text": "Meh, it's okay.", "published_date": ISODate("2017-12-06") }
通过将 10 条最新评论存储在product
集合中,在调用product
集合时仅返回所需的总体数据子集。 如果用户想查看其他评论,应用程序会调用review
collection。
提示
考虑在何处拆分数据时,应该将最常访问的数据部分放入应用程序首先加载的集合。在该示例中,以 10 条评论为间距对模式进行拆分,因为这是默认在应用程序中可见的评论数。
子集模式的权衡
使用包含更频繁访问数据的较小文档可减小工作集的整体大小。这些较小的文档可以提高应用程序最常访问的数据的读取性能。
但是,子集模式会导致数据重复。 在此示例中,评价同时保留在product
集合和reviews
集合中。 必须采取额外步骤来确保每个collection之间的评价保持一致。例如,当客户编辑其评价时,应用程序可能需要执行两项写入操作:一项是更新product
collection,另一项是更新reviews
collection。
您还必须在应用程序中实现逻辑,确保product
集合中的评论始终是该产品的最新 10 条评论。
其他示例使用案例
除产品评论外,子集模式也非常适合存储:
对博客文章的评论,即您只想默认显示最新或评分最高的评论。
电影中的演员阵容成员,当您默认只想显示具有最大角色的演员阵容成员时。