Docs 菜单
Docs 主页
/ /

按需物化视图

注意

消歧

本页讨论按需物化视图。有关标准视图的讨论,请参阅视图

要了解视图类型之间的差异,请参阅与标准视图的对比

按需物化视图是预先计算的聚合管道结果,它存储在磁盘上并从磁盘读取。按需物化视图通常是 $out 阶段的结果。

MongoDB 提供两种不同的视图类型:标准视图按需物化视图。这两种视图类型都可以返回聚合管道的结果。

  • 标准视图在您读取视图时计算得出,并且不会在磁盘中存储。

  • 按需物化视图存储在磁盘上并从磁盘读取。它们使用$merge$out阶段更新保存的数据。

    注意

    使用$merge时,可以使用变更流来监视物化视图的更改。 使用$out时,您无法监视物化视图上的更改。

标准视图使用底层集合的索引。因此,您无法直接在标准视图上创建、删除或重新构建索引,也无法获取视图上的索引列表。

您可以直接在按需物化视图上创建索引,因为它们存储在磁盘中。

按需物化视图的读取性能要优于标准视图,因为前者是从磁盘中读取,而不是作为查询的一部分通过计算得出。聚合管道越复杂,要聚合的数据量越大,这种性能优势就越明显。

本节中的示例使用示例训练数据集。要了解如何将示例数据集加载到您的 MongoDB Atlas 部署中,请参阅加载示例数据。

要在 MongoDB Atlas 用户界面中创建物化视图,请执行以下步骤:

1
  1. 如果尚未显示,请从导航栏上的 Organizations 菜单中选择包含所需项目的组织。

  2. 如果尚未显示,请从导航栏的 Projects 菜单中选择您的项目。

  3. 在侧边栏中,单击 Database 标题下的 Clusters

    会显示集群页面。

2
  1. 对于包含样本数据的集群,单击Browse Collections

  2. 在左侧导航窗格中,选择 sample_training 数据库。

  3. 选择 grades 集合。

3
4
5

聚合阶段转换要另存为视图的数据。要了解有关可用聚合阶段的更多信息,请参阅聚合阶段

对于此示例,使用 $set 阶段添加一个新字段:

  1. Select 下拉菜单中选择 $set

  2. 将以下语法添加到聚合管道编辑器,以针对 grades 集合内 scores 数组中的所有 score 值创建平均分数:

    {
    averageScore: { $avg: "$scores.score" }
    }

    MongoDB Atlas 将 averageScore 值添加到每个文档。

6
7
  1. Select 下拉菜单中选择 $out 阶段。

  2. 在聚合管道中添加以下事务语法,以将管道结果写入 sample_training 数据库中的 myView 集合:

    'myView'
  3. 单击 Save Documents(连接)。

$out 阶段将 aggregation pipeline 的结果写入指定集合,由该集合创建视图。要了解更多信息,请参阅 $out

刷新集合列表以查看 myView 集合。

要了解如何在 MongoDB Atlas 用户界面中查询 myView 集合,请参阅 MongoDB Atlas 文档中的查看、过滤和排序文档

该示例使用 sample_mflix 数据集中的 movies 集合。要了解如何加载示例数据,请参阅加载示例数据。

以下 updateMovieStats 函数定义了 movieYearStats 物化视图,其中包含按年份分类的电影的计数和平均 IMDb 评级。该函数接受 startYear 参数,用于更新从该年份发布的电影的统计信息。

updateMovieStats = function(startYear) {
db.movies.aggregate( [
{ $match: { year: { $gte: startYear } } },
{ $group: {
_id: "$year",
movieCount: { $sum: 1 },
avgRating: { $avg: "$imdb.rating" }
} },
{ $merge: { into: "movieYearStats", whenMatched: "replace" } }
] );
};
  • $match 阶段对电影进行过滤,以便仅处理 year 值大于或等于 startYear 的电影。

  • $group 阶段按 year 对电影进行分组。此阶段输出的文档具有以下形式:

    { "_id" : <year>, "movieCount" : <num>, "avgRating" : <num> }
  • $merge 阶段会将输出写入 movieYearStats 集合。

    根据 _id 字段,该阶段会检查每个聚合结果是否与现有文档匹配

对于初次运行,传入开始年份,以便使 movieYearStats 填充从该年份开始的数据:

updateMovieStats(2015);

初次运行后,db.movieYearStats.find().sort( { _id: 1 } ) 返回如下文档:

{ "_id" : 2015, "movieCount" : <num>, "avgRating" : <num> }
{ "_id" : 2016, "movieCount" : <num>, "avgRating" : <num> }
{ "_id" : 2017, "movieCount" : <num>, "avgRating" : <num> }

假设向 2016 的 movies 集合添加了一部新电影:

db.movies.insertOne( {
title: "Grove Test Movie",
year: 2016,
imdb: { rating: 7.5, votes: 500 }
} )

要刷新 movieYearStats 以及后续的 2016,请以 startYear2016 运行该函数:

updateMovieStats(2016);

更新的 movieYearStats 反映了 movies 集合中的新电影。db.movieYearStats.find().sort( { _id: 1 } ) 返回:

{ "_id" : 2015, "movieCount" : <num>, "avgRating" : <num> }
{ "_id" : 2016, "movieCount" : <num>, "avgRating" : <num> }
{ "_id" : 2017, "movieCount" : <num>, "avgRating" : <num> }

$merge 阶段:

  • 可以输出到相同或不同数据库中的集合。

  • 如果输出集合不存在,则创建一个新集合。

  • 可将结果(插入新文档、合并文档、替换文档、保留现有文档、操作失败、使用自定义更新管道处理文档)并入现有集合。

  • 可输出到分片集合。输入集合也可以是分片的。

请参阅 $merge 以了解:

后退

支持的操作

在此页面上