Make the MongoDB docs better! We value your opinion. Share your feedback for a chance to win $100.
Click here >
Docs Menu
Docs Home
/ /

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.

MongoDB provides two different view types: standard views and on-demand materialized views. Both view types return the results from an aggregation pipeline.

  • 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.

    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.

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 MongoDB Vector Search indexes on compatible views that contain only the following stages:

You can also create indexes directly on on-demand materialized views because MongoDB stores those indexes on disk.

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.

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.

To create a materialized view in the MongoDB Atlas UI, follow these steps:

1
  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. In the sidebar, click Clusters under the Database heading.

    The Clusters page displays.

2
  1. For the cluster that contains the sample data, click Browse Collections.

  2. In the left navigation pane, select the sample_training database.

  3. Select the grades collection.

3
4
5

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:

  1. Select $set from the Select drop-down menu.

  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:

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

    MongoDB Atlas adds the averageScore value to each document.

6
7
  1. Select the $out stage from the Select drop-down menu.

  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:

    '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.

Refresh the list of collections to see the myView collection.

To learn how to query the myView collection in the MongoDB Atlas UI, see View, Filter, and Sort Documents in the MongoDB Atlas documentation.

The example uses the movies collection from the sample_mflix dataset. To learn how to load sample data, see Load Sample Data.

The following updateMovieStats function defines a movieYearStats materialized view that contains the count and average IMDb rating of movies by year. The function accepts a startYear parameter to update statistics for movies released from that year forward.

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" } }
] );
};
  • The $match stage filters movies to process only those with a year value greater than or equal to startYear.

  • The $group stage groups movies by year. The documents output by this stage have the form:

    { "_id" : <year>, "movieCount" : <num>, "avgRating" : <num> }
  • The $merge stage writes the output to the movieYearStats collection.

    The stage matches on the _id field and checks if each aggregation result matches an existing document:

For the initial run, pass in a starting year to populate movieYearStats with data from that year forward:

updateMovieStats(2015);

After the initial run, db.movieYearStats.find().sort( { _id: 1 } ) returns documents like the following:

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

Assume a new movie is added to the movies collection for 2016:

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

To refresh movieYearStats for 2016 onward, run the function with a startYear of 2016:

updateMovieStats(2016);

The updated movieYearStats reflects the new movie in the movies collection. db.movieYearStats.find().sort( { _id: 1 } ) returns:

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

The $merge stage:

  • 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:

Back

Supported Operations

On this page