与嵌入式文档建立一对多关系模型img

概述img

本页介绍了一种数据模型,该模型使用嵌入式文档来描述连接数据之间的一对多关系。在单个文档中嵌入关联数据可以减少获取数据所需的读取操作次数。通常,您应该构造您的架构,以便您的应用程序在单个读取操作中接收所有必需的信息。

嵌入式文档模式

考虑以下映射赞助人和多个地址关系的示例。该示例说明了如果您需要在另一个上下文中查看许多数据实体,则嵌入优于引用的优势。patron在和 address数据之间的这种一对多关系中,patron有多个address实体。

在规范化数据模型中,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"
}

如果您的应用程序频繁检索address包含信息的数据 name,那么您的应用程序需要发出多个查询来解析引用。更理想的模式是将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集合存储每个产品的信息,包括该产品的十个最新评论:

    {
      "_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集合存储所有评论。每篇评论都包含对其所针对的产品的引用。

    {
      "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")
    }
    

通过在集合中存储十个最近的评论,在对product 集合的调用中仅返回整体数据的所需子product集。如果用户想要查看其他评论,应用程序会调用该review 集合。

[TIP]

在考虑将数据拆分到哪里时,最常访问的数据部分应该放在应用程序最先加载的集合中。在此示例中,架构被拆分为 10 个评论,因为这是默认情况下在应用程序中可见的评论数。

[TIP]

也可以看看:

要了解如何使用子集模式对集合之间的一对一关系建模,请参阅 使用嵌入式文档建模一对一关系。

子集模式的权衡

使用包含更频繁访问的数据的较小文档可以减少工作集的整体大小。这些较小的文档可以提高应用程序访问最频繁的数据的读取性能。

但是,子集模式会导致数据重复。在示例中,评论在product集合和 reviews集合中维护。必须采取额外的步骤来确保每个集合之间的评论是一致的。例如,当客户编辑他们的评论时,应用程序可能需要进行两次写操作:一次更新product集合,一次更新reviews集合。

您还必须在您的应用程序中实现逻辑,以确保product集合中的评论始终是该产品的十个最新评论。

其他示例用例

除了产品评论,子集模式也很适合存储:

  • 对博客文章的评论,默认情况下您只想显示最新或评分最高的评论。
  • 电影中的演员,默认情况下您只想显示扮演最大角色的演员。

    参见

原文 - Model One-to-Many Relationships with Embedded Documents

译者:景圣

Copyright © 上海锦木信息技术有限公司 all right reserved,powered by Gitbook文件修订时间: 2023-09-01 17:10:26

results matching ""

    No results matching ""