Docs HomeMongoDB Manual

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阶段来更新保存的数据。

Indexes索引

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

You can create indexes directly on on-demand materialized views because they are stored on disk.您可以直接在按需具体化视图上创建索引,因为它们存储在磁盘上。

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.这种性能优势随着管道的复杂性和聚合数据的大小而增加。

Example实例

Assume near the end of January 2019, the collection bakesales contains the sales information by items:假设在2019年1月底,集合bakesales包含按项目列出的销售信息:

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

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

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

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. $group阶段按年度月份对销售信息进行分组。The documents output by this stage have the form:此阶段输出的文档具有以下形式:

    { "_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" : NumberDecimal("506") }
{ "_id" : "2019-01", "sales_quantity" : 86, "sales_amount" : NumberDecimal("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: new ISODate("2019-01-28"), item: "Cake - Chocolate", quantity: 3, amount: new NumberDecimal("90") },
{ date: new ISODate("2019-01-28"), item: "Cake - Peanut Butter", quantity: 2, amount: new NumberDecimal("32") },
{ date: new ISODate("2019-01-30"), item: "Cake - Red Velvet", quantity: 1, amount: new NumberDecimal("20") },
{ date: new ISODate("2019-01-30"), item: "Cookies - Chocolate Chip", quantity: 6, amount: new NumberDecimal("24") },
{ date: new ISODate("2019-01-31"), item: "Pie - Key Lime", quantity: 2, amount: new NumberDecimal("40") },
{ date: new ISODate("2019-01-31"), item: "Pie - Banana Cream", quantity: 2, amount: new NumberDecimal("40") },
{ date: new ISODate("2019-02-01"), item: "Cake - Red Velvet", quantity: 5, amount: new NumberDecimal("100") },
{ date: new ISODate("2019-02-01"), item: "Tarts - Apple", quantity: 2, amount: new NumberDecimal("8") },
{ date: new ISODate("2019-02-02"), item: "Cake - Chocolate", quantity: 2, amount: new NumberDecimal("60") },
{ date: new ISODate("2019-02-02"), item: "Cake - Peanut Butter", quantity: 1, amount: new NumberDecimal("16") },
{ date: new ISODate("2019-02-03"), item: "Cake - Red Velvet", quantity: 5, amount: new NumberDecimal("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" : NumberDecimal("506") }
{ "_id" : "2019-01", "sales_quantity" : 102, "sales_amount" : NumberDecimal("1142") }
{ "_id" : "2019-02", "sales_quantity" : 15, "sales_amount" : NumberDecimal("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,了解: