Database Manual / Introduction / Databases & Collections

On-Demand Materialized Views按需物化视图

Note

Disambiguation消歧

This page discusses on-demand materialized views. For discussion of standard views, see Views.本页讨论按需物化视图。有关标准视图的讨论,请参阅视图。

To understand the differences between the view types, see Comparison with Standard Views.要了解视图类型之间的差异,请参阅与标准视图的比较

An on-demand materialized view is a pre-computed aggregation pipeline result that is stored on and read from disk. On-demand materialized views are typically the results of a $merge or $out stage.按需物化视图是存储在磁盘上并从磁盘读取的预先计算的聚合管道结果。按需物化视图通常是$merge$out阶段的结果。

Comparison with Standard Views与标准视图的比较

MongoDB provides two different view types: standard views and on-demand materialized views. Both view types return the results from an aggregation pipeline.MongoDB提供了两种不同的视图类型:标准视图按需物化视图。这两种视图类型都返回聚合管道的结果。

  • Standard views are computed when you read the view, and are not stored to disk.标准视图是在您读取视图时计算的,不会存储到磁盘上。
  • On-demand materialized views are stored on and read from disk. They use a $merge or $out stage to update the saved data.按需物化视图存储在磁盘上并从磁盘读取。他们使用$merge$out阶段来更新保存的数据。

    Note

    When using $merge, you can use change streams to watch for changes on the materialized view. When using $out, you can't watch for changes on the materialized view.使用$merge时,您可以使用更改流来监视物化视图上的更改。使用$out时,您无法观察物化视图上的变化。

Indexes索引

Standard views use the indexes of the underlying collection. As a result, you cannot create, drop or re-build general indexes on a standard view directly, nor get a list of general indexes on the view.标准视图使用基础集合的索引。因此,您无法直接在标准视图上创建、删除或重新构建常规索引,也无法在视图上获取常规索引列表。

MongoDB stores search indexes and vector search indexes on disk. Accordingly, you can create MongoDB Search indexes and Vector Search indexes on compatible views that contain only the following stages:MongoDB在磁盘上存储搜索索引矢量搜索索引。因此,您可以在仅包含以下阶段的兼容视图上创建MongoDB搜索索引和矢量搜索索引:

You can also create indexes directly on on-demand materialized views because MongoDB stores those indexes on disk.您还可以直接在按需物化视图上创建索引,因为MongoDB将这些索引存储在磁盘上。

Performance性能

On-demand materialized views provide better read performance than standard views because they are read from disk instead of computed as part of the query. This performance benefit increases based on the complexity of the pipeline and size of the data being aggregated.按需物化视图提供了比标准视图更好的读取性能,因为它们是从磁盘读取的,而不是作为查询的一部分计算的。这种性能优势会随着管道的复杂性和聚合数据的大小而增加。

Create a Materialized View in the MongoDB Atlas UI在MongoDB Atlas UI中创建物化视图

The example in this section uses the sample training dataset. To learn how to load the sample dataset into your MongoDB Atlas deployment, see Load Sample Data.本节中的示例使用示例训练数据集。要了解如何将示例数据集加载到MongoDB Atlas部署中,请参阅加载示例数据

To create a materialized view in the MongoDB Atlas UI, follow these steps:要在MongoDB Atlas UI中创建物化视图,请执行以下步骤:

1

In the MongoDB Atlas UI, go to the Clusters page for your project.在MongoDB Atlas UI中,转到项目的“集群”页面。

Warning

Navigation Improvements In Progress导航改进正在进行中

We're currently rolling out a new and improved navigation experience. If the following steps don't match your view in the Atlas UI, see the preview Atlas documentation.我们目前正在推出一种新的、改进的导航体验。如果以下步骤与Atlas UI中的视图不匹配,请参阅Atlas预览文档

  1. If it's not already displayed, select the organization that contains your desired project from the Organizations menu in the navigation bar.如果尚未显示,请从导航栏的“组织”菜单中选择包含所需项目的组织。
  2. If it's not already displayed, select your project from the Projects menu in the navigation bar.如果尚未显示,请从导航栏中的“项目”菜单中选择您的项目。
  3. If it's not already displayed, click Clusters in the sidebar.如果尚未显示,请单击侧栏中的“集群”。
    The Clusters page displays.将显示“群集”页面。
2

Navigate to the collection导航到集合

  1. For the cluster that contains the sample data, click Browse Collections.对于包含示例数据的集群,单击“浏览集合”。
  2. In the left navigation pane, select the sample_training database.在左侧导航窗格中,选择“sample_training”数据库。
  3. Select the grades collection.选择grades集合。
3

Click the Aggregation tab单击“聚合”选项卡

4

Click Add Stage单击“添加阶段”

5

Select an aggregation stage from the Select drop-down menu从“选择”下拉菜单中选择聚合阶段

The aggregation stage transforms the data that you want to save as a view. To learn more about available aggregation stages, see Aggregation Stages.聚合阶段转换要另存为视图的数据。要了解有关可用聚合阶段的更多信息,请参阅聚合阶段

For this example, add a new field with the $set stage:对于此示例,使用$set阶段添加一个新字段:

  1. Select $set from the Select drop-down menu.从“选择”下拉菜单中选择$set
  2. Add the following syntax to the aggregation pipeline editor to create an average score across all score values in the scores array within the grades collection:将以下语法添加到聚合管道编辑器中,以创建grades(成绩)集合中scores数组中所有score(分数)值的平均分数:
    {
    averageScore: { $avg: "$scores.score" }
    }
    MongoDB Atlas adds the averageScore value to each document.MongoDB Atlas将averageScore值添加到每个文档中。
6

Click Add Stage单击“添加阶段”

7

Add the $out stage添加$out阶段

  1. Select the $out stage from the Select drop-down menu.从“选择”下拉菜单中选择$out阶段。
  2. Add the following syntax to the aggregation pipeline to write the results of the pipeline to the myView collection in the sample_training database:将以下语法添加到聚合管道中,以将管道的结果写入sample_training数据库中的myView集合:
    'myView'
  3. Click Save Documents.单击“保存文档”。

The $out stage writes the results of the aggregation pipeline to the specified collection, which creates the view. To learn more, see $out.$out阶段将聚合管道的结果写入指定的集合,从而创建视图。要了解更多信息,请参阅$out

Refresh the list of collections to see the myView collection.刷新集合列表以查看myView集合。

To learn how to query the myView collection in the MongoDB Atlas UI, see View, Filter, and Sort Documents in the MongoDB Atlas documentation.要了解如何在MongoDB Atlas UI中查询myView集合,请参阅MongoDB Atlas文档中的查看、筛选和排序文档

Example示例

Assume near the end of January 2019, the collection bakesales contains the sales information by items:假设在2019年1月底左右,集合bakesales(烘焙品)包含按商品分类的销售信息:

db.bakesales.insertMany( [
{ date: ISODate("2018-12-01"), item: "Cake - Chocolate", quantity: 2, amount: Decimal128("60") },
{ date: ISODate("2018-12-02"), item: "Cake - Peanut Butter", quantity: 5, amount: Decimal128("90") },
{ date: ISODate("2018-12-02"), item: "Cake - Red Velvet", quantity: 10, amount: Decimal128("200") },
{ date: ISODate("2018-12-04"), item: "Cookies - Chocolate Chip", quantity: 20, amount: Decimal128("80") },
{ date: ISODate("2018-12-04"), item: "Cake - Peanut Butter", quantity: 1, amount: Decimal128("16") },
{ date: ISODate("2018-12-05"), item: "Pie - Key Lime", quantity: 3, amount: Decimal128("60") },
{ date: ISODate("2019-01-25"), item: "Cake - Chocolate", quantity: 2, amount: Decimal128("60") },
{ date: ISODate("2019-01-25"), item: "Cake - Peanut Butter", quantity: 1, amount: Decimal128("16") },
{ date: ISODate("2019-01-26"), item: "Cake - Red Velvet", quantity: 5, amount: Decimal128("100") },
{ date: ISODate("2019-01-26"), item: "Cookies - Chocolate Chip", quantity: 12, amount: Decimal128("48") },
{ date: ISODate("2019-01-26"), item: "Cake - Carrot", quantity: 2, amount: Decimal128("36") },
{ date: ISODate("2019-01-26"), item: "Cake - Red Velvet", quantity: 5, amount: Decimal128("100") },
{ date: ISODate("2019-01-27"), item: "Pie - Chocolate Cream", quantity: 1, amount: Decimal128("20") },
{ date: ISODate("2019-01-27"), item: "Cake - Peanut Butter", quantity: 5, amount: Decimal128("80") },
{ date: ISODate("2019-01-27"), item: "Tarts - Apple", quantity: 3, amount: Decimal128("12") },
{ date: ISODate("2019-01-27"), item: "Cookies - Chocolate Chip", quantity: 12, amount: Decimal128("48") },
{ date: ISODate("2019-01-27"), item: "Cake - Carrot", quantity: 5, amount: Decimal128("36") },
{ date: ISODate("2019-01-27"), item: "Cake - Red Velvet", quantity: 5, amount: Decimal128("100") },
{ date: ISODate("2019-01-28"), item: "Cookies - Chocolate Chip", quantity: 20, amount: Decimal128("80") },
{ date: ISODate("2019-01-28"), item: "Pie - Key Lime", quantity: 3, amount: Decimal128("60") },
{ date: ISODate("2019-01-28"), item: "Cake - Red Velvet", quantity: 5, amount: Decimal128("100") },
] );

1. Define the On-Demand Materialized View定义按需物化视图

The following updateMonthlySales function defines a monthlybakesales materialized view that contains the cumulative monthly sales information. In the example, the function takes a date parameter to only update monthly sales information starting from a particular date.以下updateMonthlySales函数定义了一个包含累积月度销售信息的monthlybakesales物化视图。在该示例中,该函数采用日期参数,仅更新从特定日期开始的每月销售信息。

updateMonthlySales = function(startDate) {
db.bakesales.aggregate( [
{ $match: { date: { $gte: startDate } } },
{ $group: { _id: { $dateToString: { format: "%Y-%m", date: "$date" } }, sales_quantity: { $sum: "$quantity"}, sales_amount: { $sum: "$amount" } } },
{ $merge: { into: "monthlybakesales", whenMatched: "replace" } }
] );
};
  • The $match stage filters the data to process only those sales greater than or equal to the startDate.$match阶段筛选数据,仅处理大于或等于startDate的销售。
  • The $group stage groups the sales information by the year-month. The documents output by this stage have the form:$group阶段按年月对销售信息进行分组。此阶段输出的文档具有以下形式:
    { "_id" : "<YYYY-mm>", "sales_quantity" : <num>, "sales_amount" : <NumberDecimal> }
  • The $merge stage writes the output to the monthlybakesales collection.$merge阶段将输出写入monthlybakesales集合。

    Based on the _id field (the default for unsharded output collections), the stage checks if the document in the aggregation results matches an existing document in the collection:根据_id字段(未记录输出集合的默认值),该阶段检查聚合结果中的文档是否与集合中的现有文档匹配

2. Perform Initial Run执行初始运行

For the initial run, you can pass in a date of new ISODate("1970-01-01"):对于首次运行,您可以传入日期new ISODate("1970-01-01")

updateMonthlySales(new ISODate("1970-01-01"));

After the initial run, the monthlybakesales contains the following documents; i.e. db.monthlybakesales.find().sort( { _id: 1 } ) returns the following:初次运行后,monthlybakesales(月度烘焙产品)包含以下文件:;即db.monthlybakesales.find().sort( { _id: 1 } )返回以下结果:

{ "_id" : "2018-12", "sales_quantity" : 41, "sales_amount" : Decimal128("506") }
{ "_id" : "2019-01", "sales_quantity" : 86, "sales_amount" : Decimal128("896") }

3. Refresh Materialized View刷新物化视图

Assume that by the first week in February 2019, the bakesales collection is updated with newer sales information; specifically, additional January and February sales.假设到2019年2月的第一周,bakesales集合已更新为新的销售信息;特别是1月和2月的额外销售。

db.bakesales.insertMany( [
{ date: ISODate("2019-01-28"), item: "Cake - Chocolate", quantity: 3, amount: Decimal128("90") },
{ date: ISODate("2019-01-28"), item: "Cake - Peanut Butter", quantity: 2, amount: Decimal128("32") },
{ date: ISODate("2019-01-30"), item: "Cake - Red Velvet", quantity: 1, amount: Decimal128("20") },
{ date: ISODate("2019-01-30"), item: "Cookies - Chocolate Chip", quantity: 6, amount: Decimal128("24") },
{ date: ISODate("2019-01-31"), item: "Pie - Key Lime", quantity: 2, amount: Decimal128("40") },
{ date: ISODate("2019-01-31"), item: "Pie - Banana Cream", quantity: 2, amount: Decimal128("40") },
{ date: ISODate("2019-02-01"), item: "Cake - Red Velvet", quantity: 5, amount: Decimal128("100") },
{ date: ISODate("2019-02-01"), item: "Tarts - Apple", quantity: 2, amount: Decimal128("8") },
{ date: ISODate("2019-02-02"), item: "Cake - Chocolate", quantity: 2, amount: Decimal128("60") },
{ date: ISODate("2019-02-02"), item: "Cake - Peanut Butter", quantity: 1, amount: Decimal128("16") },
{ date: ISODate("2019-02-03"), item: "Cake - Red Velvet", quantity: 5, amount: Decimal128("100") }
] )

To refresh the monthlybakesales data for January and February, run the function again to rerun the aggregation pipeline, starting with new ISODate("2019-01-01").要刷新1月和2月的monthlybakesales(月度烘焙销售)数据,请再次运行该函数以重新运行聚合管道,从new ISODate("2019-01-01")开始。

updateMonthlySales(new ISODate("2019-01-01"));

The content of monthlybakesales has been updated to reflect the most recent data in the bakesales collection; i.e. db.monthlybakesales.find().sort( { _id: 1 } ) returns the following:monthlybakesales的内容已经更新,以反映bakesales集合中的最新数据;即db.monthlybakesales.find().sort( { _id: 1 } )返回以下结果:

{ "_id" : "2018-12", "sales_quantity" : 41, "sales_amount" : Decimal128("506") }
{ "_id" : "2019-01", "sales_quantity" : 102, "sales_amount" : Decimal128("1142") }
{ "_id" : "2019-02", "sales_quantity" : 15, "sales_amount" : Decimal128("284") }

Additional Information附加信息

The $merge stage:$merge阶段:

  • Can output to a collection in the same or different database.可以输出到相同或不同数据库中的集合。
  • Creates a new collection if the output collection does not already exist.如果输出集合不存在,则创建新集合。
  • Can incorporate results (insert new documents, merge documents, replace documents, keep existing documents, fail the operation, process documents with a custom update pipeline) into an existing collection.可以将结果(插入新文档、合并文档、替换文档、保留现有文档、操作失败、使用自定义更新管道处理文档)合并到现有集合中。
  • Can output to a sharded collection. Input collection can also be sharded.可以输出到分片集合。输入集合也可以分片。

See $merge for:请参阅$merge了解: