# MongoDB View

## Summary


MongoDB's aggregation pipeline processes documents of a collection through one or more stages. Views are read-only results of such aggregations. With views, consumers can simply read those results without needing to execute the aggregation pipeline again. 

MongoDB's views are **non-materialized** by nature, that is, the views are created and updated on the fly. Results are not persisted on disks. Since MongoDB 4.2, **on-demand materialized views** are also possible with the `$merge` pipeline stage. Such views are stored in an output collection that are updated every time the pipeline is executed. 

Views are useful for many use cases. They bring benefits in terms of data privacy, performance tuning, code reuse, and analytics. Non-materialized views take up very little storage: view data is not stored, only view definition is stored. Views add a layer of abstraction between the application and complex aggregation pipelines.

## Discussion

### What are some use cases for MongoDB views?

An organization's employee data can have sensitive information. When exposing this data to applications, personal and private information can be excluded in a view. An alternative to exclusion, is to pseudonymize fields, which is necessary for regulatory compliance such as for GDPR. Applications have access only to the view, not the underlying collection. 

In IoT, applications may not require every single measurement provided by the sensors. In many cases, they require only aggregates: counts, min/max values, averages, etc. A view stores these aggregates and keeps them updated as new data arrives. A specific example is a collection that contains daily rainfall. A view stores monthly averages, which can then be more easily queried for driest and wettest months. 

When analysis requires data from multiple collections, views can offer applications a simpler interface. Applications need not be burdened with the underlying complex pipelines. For example, a view can bring together data from Inventory and Orders collection in an e-commerce application. 


### Could you describe MongoDB view with an example?

Consider Game of Thrones data. Documents of the `characters` collection has names plus status. Status is optional and its value is either dead or alive. Status field can be considered as a spoiler. We wish to hide it for some consumers of this data. 

We project the status field thus, `"status" : { "$cond": [{ "$eq": [ "$status", undefined ] }, $status = "Not Specified", $status = "&ast;&ast;&ast;&ast;*" ] }`. If undefined, we set it to `Not Specified`. Otherwise, we mask it with `&ast;&ast;&ast;&ast;*`. 

The above projection can be used in a pipeline on the `characters` collection and the result stored in a view named `charactersNoSpoil`: `db.createView("charactersNoSpoil", "characters", <pipeline>)`. In addition, we could also include only some fields in the view via the projection. 

Once views are setup this way, we can restrict access using `db.createRole()` and `db.createUser()`. It's also possible to enable auditing and analyse the logs to verify that access privileges are working as expected. 


### Can I create materialized views in MongoDB?

Since MongoDB 4.2, on-demand materialized views are possible. The output can be stored in a collection in the same or different database. The output collection could be a sharded one. If collection doesn't exist, it's created. Results can go into an existing collection with the ability to merge/replace/keep existing documents, fail the operation or process documents with an custom update pipeline. On-demand materialized views are implemented via the `$merge` pipeline stage.  

The figure shows an example of `monthlybakesales` materialized view created from `bakesales` collection. The pipeline preceding the view groups data by year and month, and stores sales quantity and amount. When new sales figures are obtained for January 2019 and later, the view is updated by calling `updateMonthlySales(new ISODate("2019-01-01"));`. 

In the above example, the input and output are in the same database. If we plan to store the view in a different database named `reporting`, we can use the following syntax within `$merge`: `into: { db: "reporting", coll: "monthlybakesales" }`. For merging, documents are identified using `_id` field by default but `on` field can be used to customize this. 


### How do I deal with indexes for MongoDB views?

Views use indexes of the underlying collection. This also means that we can't create, drop or rebuild indexes directly on views. 

For on-demand materialized views, it's possible to create indexes. Indexes have to be unique as mandated by the `$merge` stage. An example of creating a unique index is `db.metricsByWeek.createIndex({week:1}, {unique:true})`. This can be used for merging with the field `on: "week"` or `on: ["week"]`. 

## Milestones

Feb  
2009

**MongoDB 1.0** is released. By August, this version becomes generally available for production environments. 

Nov  
2016

MongoDB 3.4 is released with support for **creating read-only views** from existing collections or other views. Options `viewOn` and `pipeline` are added to the existing `create` command. On the `mongo` shell, the corresponding helper is `db.createView()`. 

Aug  
2019

MongoDB 4.2 is released. With the newly added stage `$merge`, we can create **on-demand materialized views**. Prior to MongoDB 4.2, `db.createView()` obtained exclusive lock on the parent database. With this release, exclusive lock is obtained only for the input collection or view. MongoDB Compass 1.19 is released. There's now support for **views in Compass**. 

Jul  
2020

MongoDB 4.4 is released. When running `find` operation on a view, `$natural` sort is now possible. This is the order in which the database refers to documents on disk.