A MongoDB view is a queryable object whose contents are defined by an aggregation pipeline on other collections or views. MongoDB does not persist the view contents to disk. A view's content is computed on-demand when a client queries the view. MongoDB can require clients to have permission to query the view. MongoDB does not support write operations against views.
For example, you can:
Create a view on a collection of employee data to
excludeany private or personal information (PII). Applications can query the view for employee data that does not contain any PII.Create a view on a collection of collected sensor data to
addcomputed fields and metrics. Applications can use simple find operations to query the data.Create a view that
joinstwo collections containing inventory and order history respectively. Applications can query the joined data without managing or understanding the underlying complex pipeline.
You can create materialized views in the UI for deployments hosted in MongoDB Atlas.
When clients query a view, MongoDB appends the client query to the underlying pipeline and returns the results of that combined pipeline to the client. MongoDB may apply aggregation pipeline optimizations to the combined pipeline.
Note
The following page discusses views. For discussion of on-demand materialized views, see On-Demand Materialized Views instead.
Create View
To create or define a view:
Use the
db.createCollection()method or thecreatecommand:db.createCollection( "<viewName>", { "viewOn" : "<source>", "pipeline" : [<pipeline>], "collation" : { <collation> } } ) Use the
db.createView()method:db.createView( "<viewName>", "<source>", [<pipeline>], { "collation" : { <collation> } } )
Note
- You must create views in the same database as the source collection.
Warning
Do not attempt to create a time series collection or view with the
name system.profile because the MongoDB server will crash.
Behavior
Views exhibit the following behavior:
Read Only
Views are read-only; write operations on views will error.
The following read operations can support views:
Index Use and Sort Operations
Views use the indexes of the underlying collection.
As the indexes are on the underlying collection, you cannot create, drop or re-build indexes on the view directly nor get a list of indexes on the view.
Starting in MongoDB 4.4, you can specify a
$naturalsort when running afindcommand on a view. Prior versions of MongoDB do not support$naturalsort on views.The view's underlying aggregation pipeline is subject to the 100 megabyte memory limit for blocking sort and blocking group operations. Starting in MongoDB 4.4, you can issue a
findcommand withallowDiskUse: trueon the view to allow MongoDB to use temporary files for blocking sort and group operations.Prior to MongoDB 4.4, only the
aggregatecommand accepted theallowDiskUseoption.Tip
For more information on blocking sort operation memory limits, see Sort Operations.
Projection Restrictions
find() operations on views do not support
the following projection
operators:
Immutable Name
You cannot rename views.
View Creation
Views are computed on demand during read operations, and MongoDB executes read operations on views as part of the underlying aggregation pipeline. As such, views do not support operations such as:
If the aggregation pipeline used to create the view suppresses the
_idfield, documents in the view do not have the_idfield.
When you query a view, the:
Query
filter,projection,sort,skip,limit, and other operations fordb.collection.find()are converted to the equivalent aggregation pipeline stages.Converted aggregation pipeline stages are added to the end of the aggregation pipeline for the view. This does not modify the view's underlying pipeline, which is set when you create the view.
Aggregation pipeline optimizer reshapes the view aggregation pipeline stages to improve performance. This does not change the query results.
Sharded View
Views are considered sharded if their underlying collection is
sharded. As such, you cannot specify a sharded view for the from
field in $lookup and $graphLookup operations.
Views and Collation
You can specify a default collation for a view at creation time. If no collation is specified, the view's default collation is the "simple" binary comparison collator. That is, the view does not inherit the collection's default collation.
String comparisons on the view use the view's default collation. An operation that attempts to change or override a view's default collation will fail with an error.
If creating a view from another view, you cannot specify a collation that differs from the source view's collation.
If performing an aggregation that involves multiple views, such as with
$lookupor$graphLookup, the views must have the same collation.
Snapshot Isolation
Views do not maintain timestamps of collection changes and do not support point-in-time or snapshot read isolation.
Public View Definition
Operations that lists collections, such as
db.getCollectionInfos() and
db.getCollectionNames(), include views in their outputs.
Important
The view definition is public; i.e. db.getCollectionInfos()
and explain operations on the view will include the pipeline that
defines the view. As such, avoid referring directly to sensitive fields
and values in view definitions.
Drop a View
To remove a view, use the db.collection.drop() method on the
view.
Modify a View
You can modify a view either by dropping and recreating the view or
using the collMod command.
Supported Operations
The following operations provide support for views, except for the restrictions mentioned in this page:
Commands | Methods |
|---|---|
Examples
Create the students collection to use in the following examples:
db.students.insertMany( [ { sID: 22001, name: "Alex", year: 1, score: 4.0 }, { sID: 21001, name: "bernie", year: 2, score: 3.7 }, { sID: 20010, name: "Chris", year: 3, score: 2.5 }, { sID: 22021, name: "Drew", year: 1, score: 3.2 }, { sID: 17301, name: "harley", year: 6, score: 3.1 }, { sID: 21022, name: "Farmer", year: 1, score: 2.2 }, { sID: 20020, name: "george", year: 3, score: 2.8 }, { sID: 18020, name: "Harley", year: 5, score: 2.8 }, ] )
Use db.createView() to Create a View
Use db.createView() to create a view that is limited to first
year students:
db.createView( "firstYears", "students", [ { $match: { year: 1 } } ] )
In the example:
firstYearsis the name of the new view.studentsis the collection the view is based on.$matchis an aggregation expression that matches first year students in thestudentscollection.
This example queries the view:
db.firstYears.find({}, { _id: 0 } )
The following output only contains the documents with data on first
year students. The { _id: 0 } projection suppresses the _id field in the output.
[ { sID: 22001, name: 'Alex', year: 1, score: 4 }, { sID: 22021, name: 'Drew', year: 1, score: 3.2 }, { sID: 21022, name: 'Farmer', year: 1, score: 2.2 } ]
Use db.createCollection() to Create a View
The db.createCollection() method allows you to create a
collection or a view with specific options.
The following example creates a graduateStudents view. The view
only contains documents selected by the $match stage. The
optional collation setting determines the sort
order.
db.createCollection( "graduateStudents", { viewOn: "students", pipeline: [ { $match: { $expr: { $gt: [ "$year", 4 ] } } } ], collation: { locale: "en", caseFirst: "upper" } } )
The following example queries the view. The $unset stage
removes the _id field from the output for clarity.
db.graduateStudents.aggregate( [ { $sort: { name: 1 } }, { $unset: [ "_id" ] } ] )
When the output is sorted, the $sort stage uses the
collation ordering to sort uppercase letters before
lowercase letters.
[ { sID: 18020, name: 'Harley', year: 5, score: 2.8 }, { sID: 17301, name: 'harley', year: 6, score: 3.1 } ]
Use a View to Join Two Collections
It is often convenient to use $lookup to create a view over
two collections and then run queries against the view. Applications can
query the view without having to construct or maintain complex
pipelines.
Create two sample collections, inventory and orders:
db.inventory.insertMany( [ { prodId: 100, price: 20, quantity: 125 }, { prodId: 101, price: 10, quantity: 234 }, { prodId: 102, price: 15, quantity: 432 }, { prodId: 103, price: 17, quantity: 320 } ] ) db.orders.insertMany( [ { orderID: 201, custid: 301, prodId: 100, numPurchased: 20 }, { orderID: 202, custid: 302, prodId: 101, numPurchased: 10 }, { orderID: 203, custid: 303, prodId: 102, numPurchased: 5 }, { orderID: 204, custid: 303, prodId: 103, numPurchased: 15 }, { orderID: 205, custid: 303, prodId: 103, numPurchased: 20 }, { orderID: 206, custid: 302, prodId: 102, numPurchased: 1 }, { orderID: 207, custid: 302, prodId: 101, numPurchased: 5 }, { orderID: 208, custid: 301, prodId: 100, numPurchased: 10 }, { orderID: 209, custid: 303, prodId: 103, numPurchased: 30 } ] )
Create a view that combines elements from each collection:
db.createView( "sales", "orders", [ { $lookup: { from: "inventory", localField: "prodId", foreignField: "prodId", as: "inventoryDocs" } }, { $project: { _id: 0, prodId: 1, orderId: 1, numPurchased: 1, price: "$inventoryDocs.price" } }, { $unwind: "$price" } ] )
In the example:
db.createView()creates thesalesview.The
salesview is based on theorderscollection.The
$lookupstage uses theprodIdfield in theorderscollection to "join" documents in theinventorycollection that have matchingprodIdfields.The matching documents are added as an array in the
inventoryDocsfield.The
$projectstage selects a subset of the available fields.The
$unwindstage converts thepricefield from an array to a scalar value.
The documents in the sales view are:
{ prodId: 100, numPurchased: 20, price: 20 }, { prodId: 101, numPurchased: 10, price: 10 }, { prodId: 102, numPurchased: 5, price: 15 }, { prodId: 103, numPurchased: 15, price: 17 }, { prodId: 103, numPurchased: 20, price: 17 }, { prodId: 102, numPurchased: 1, price: 15 }, { prodId: 101, numPurchased: 5, price: 10 }, { prodId: 100, numPurchased: 10, price: 20 }, { prodId: 103, numPurchased: 30, price: 17 }
To find the total amount sold of each product, query the view:
db.sales.aggregate( [ { $group: { _id: "$prodId", amountSold: { $sum: { $multiply: [ "$price", "$numPurchased" ] } } } } ] )
The output is:
[ { _id: 100, amountSold: 600 }, { _id: 103, amountSold: 1105 }, { _id: 101, amountSold: 150 }, { _id: 102, amountSold: 90 } ]