文档菜单
文档首页
/
MongoDB 手册
/ / /

使用异常模式分组数据

本页内容

  • 开始之前
  • 优点
  • 缺点
  • 关于此任务
  • 步骤
  • 确定异常的阈值
  • 决定如何处理异常
  • 为异常文档添加指示器
  • 将额外的销售存储在单独的集合中
  • 结果
  • 异常更新
  • 了解更多

如果您的集合存储的文档大小和形状大致相同,一个与预期截然不同的文档(异常)可能会对常见查询的性能造成问题。

考虑一个存储数组字段的集合。如果一个文档包含的数组元素比集合中的其他文档多得多,您可能需要在模式中对该文档进行不同的处理。

使用异常模式将不匹配预期形状的文档与集合的其他部分隔离开来。您的模式仍然保留了所有相同的数据,但常见查询不会受到单个大型文档的影响。

在修改您的架构以处理异常值之前,考虑异常值模式的优缺点

异常值模式提高了常用查询的性能。返回典型文档的查询不需要也返回大异常值文档。

异常值模式还处理了应用中的边缘情况。例如,如果您的应用通常从一个数组中显示50个结果,就不会有一个包含2,000个结果的文档来破坏用户体验。

异常值模式需要更复杂的逻辑来处理更新。如果您经常需要更新数据,您可能需要考虑其他架构设计模式。更多信息请参见异常更新.

考虑一个跟踪书籍销售的架构。该集合中的典型文档看起来像这样

db.sales.insertOne(
{
"_id": 1,
"title": "Invisible Cities",
"year": 1972,
"author": "Italo Calvino",
"customers_purchased": [ "user00", "user01", "user02" ]
}
)

customers_purchased 数组是 无界的,这意味着随着更多客户购买书籍,该数组会变大。对于大多数文档来说,这不会成问题,因为商店不期望特定书籍的销售量会超过几笔。

假设一本新出版的热门书籍导致了大量购买。当前的架构设计会导致文档膨胀,这会负面影响性能。为了解决这个问题,为那些没有典型销售量的文档实施异常模式。

1

根据您架构中典型文档的结构,确定何时一个文档成为异常值。阈值可能基于您应用程序的UI需求,或者您对文档执行的查询。

在这个例子中,销量超过50本的书籍被视为异常值。

2

当处理大型数组时,处理异常值的一种常见方法是将在阈值之外的价值存储在单独的集合中。对于销量超过50册的书籍,将额外的 customers_purchased 值存储在单独的集合中。

3

对于销量超过50册的书籍,添加一个新的文档字段 has_extras 并将其值设置为 true。此字段指示还有更多的销量存储在单独的集合中。

db.sales.insertOne(
{
"_id": 2,
"title": "The Wooden Amulet",
"year": 2023,
"author": "Lesley Moreno",
"customers_purchased": [ "user00", "user01", "user02", ... "user49" ],
"has_extras": true
}
)
4

创建一个名为 extra_sales 的集合来存储超出初始50的销量。使用引用将 extra_sales 集合中的文档链接到 sales 集合。

db.extra_sales.insertOne(
{
"book_id": 2,
"customers_purchased_extra": [ "user50", "user51", "user52", ... "user999" ]
}
)

异常模式阻止非典型文档影响查询性能。结果架构避免了集合中的大文档,同时保持销售的全列表。

考虑一个显示一本书信息和购买此书的所有用户的页面。在实现异常模式后,页面可以快速显示大多数书(典型文档)的信息。

对于热门书籍(异常),应用程序在extra_sales集合上针对book_id执行额外查询。为了提高此查询的性能,您可以在book_id字段上创建索引。

您需要对异常文档的更新不同于典型文档。您用于执行更新的逻辑取决于您的架构设计。

为了更新前面架构中的异常,实现以下应用程序逻辑

  • 检查正在更新的文档是否将has_extras设置为true

    • 如果has_extras不存在或为false,将新购买的订单添加到sales集合。

      • 如果结果customers_purchased数组包含超过50个元素,将has_extras设置为true

    • 如果has_extrastrue,将新购买的订单添加到对应book_idsales_extras集合。

  • 使用桶模式分组数据

  • 避免无界数组

  • 嵌入式数据与引用

  • 存储计算数据

返回

桶模式