On-Demand Materialized Views按需物化视图

Note注意

The following page discusses on-demand materialized views. 下一页讨论按需物化视图。For discussion of views, see Views instead.有关视图的讨论,请参阅视图

Starting in version 4.2, MongoDB adds the $merge stage for the aggregation pipeline. 从4.2版开始,MongoDB为聚合管道添加了$merge阶段。This stage can merge the pipeline results to an existing collection instead of completely replacing the collection. 此阶段可以将管道结果合并到现有集合,而不是完全替换集合。This functionality allows users to create on-demand materialized views, where the content of the output collection can be updated each time the pipeline is run.此功能允许用户创建按需物化视图,每次管道运行时都可以更新输出集合的内容。

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

←  ViewsCapped Collections →