To create a view, use one of the following methods:
Use
db.createView()
To create a view in the MongoDB Atlas UI, use the Aggregation Pipeline Builder. To learn more, see Manage Views in Atlas.
Important
View Names are Included in Collection List Output
Operations that list collections, such as db.getCollectionInfos() and db.getCollectionNames(), include views in their outputs.
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.
db.createCollection() Syntax
db.createCollection( "<viewName>", { "viewOn" : "<source>", "pipeline" : [<pipeline>], "collation" : { <collation> } } )
db.createView() Syntax
db.createView( "<viewName>", "<source>", [<pipeline>], { "collation" : { <collation> } } )
Restrictions
You must create views in the same database as the source collection.
You cannot rename a view once it is created.
Unsupported Operations
Some operations are not available with views:
$textoperator, since$textin aggregation is valid only for the first stage.Renaming a view.
For more information, see Supported Operations for Views.
Examples
Populate the Collection
Create a students collection to use for this example:
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
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.
Query the View
db.firstYears.find({}, { _id: 0 } )
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 } ]
Note
Projection Restrictions
find() operations on views do not support the following find command projection operators:
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: { year: { $gt: 4 } } } ], collation: { locale: "en", caseFirst: "upper" } } )
Note
Collation Behavior
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.
Query the View
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 } ]
Retrieve Medical Information for Roles Granted to the Current User
Starting in MongoDB 7.0, you can use the new USER_ROLES system variable to return user roles.
Note
Using the USER_ROLES system variable in aggregations is not supported in M0 and Flex clusters.
The example in this section shows users with limited access to fields in a collection containing medical information. The example uses a view that reads the current user roles from the USER_ROLES system variable and hides fields based on the roles.
The example creates these users:
Jameswith aBillingrole who can access acreditCardfield.Michellewith aProviderrole who can access adiagnosisCodefield.
Perform the following steps to create the roles, users, collection, and view:
Create the roles
Run:
db.createRole( { role: "Billing", privileges: [ { resource: { db: "test", collection: "medicalView" }, actions: [ "find" ] } ], roles: [ ] } ) db.createRole( { role: "Provider", privileges: [ { resource: { db: "test", collection: "medicalView" }, actions: [ "find" ] } ], roles: [ ] } )
Create the users
Create users named James and Michelle with the required roles. Replace the test database with your database name.
db.createUser( { user: "James", pwd: "js008", roles: [ { role: "Billing", db: "test" } ] } ) db.createUser( { user: "Michelle", pwd: "me009", roles: [ { role: "Provider", db: "test" } ] } )
Create the view
To use a system variable, add $$ to the start of the variable name. Specify the USER_ROLES system variable as $$USER_ROLES.
The view reads the current user roles from the USER_ROLES system variable and hides fields based on the roles.
Run:
db.createView( "medicalView", "medical", [ { $set: { "diagnosisCode": { $cond: { if: { $in: [ "Provider", "$$USER_ROLES.role" ] }, then: "$diagnosisCode", else: "$$REMOVE" } } }, }, { $set: { "creditCard": { $cond: { if: { $in: [ "Billing", "$$USER_ROLES.role" ] }, then: "$creditCard", else: "$$REMOVE" } } } } ] )
The view example:
includes the
diagnosisCodefield for a user with theProviderrole.includes the
creditCardfield for a user with theBillingrole.
Perform the following steps to retrieve the information accessible to James:
Perform the following steps to retrieve the information accessible to Michelle:
Retrieve Budget Documents for Roles Granted to the Current User
Starting in MongoDB 7.0, you can use the new USER_ROLES system variable to return user roles.
The scenario in this section shows users with various roles who have limited access to documents in a collection containing budget information.
The scenario shows one possible use of USER_ROLES. The budget collection contains documents with a field named allowedRoles. As you'll see in the following scenario, you can write queries that compare the user roles found in the allowedRoles field with the roles returned by the USER_ROLES system variable.
Note
For another USER_ROLES example scenario, see Retrieve Medical Information for Roles Granted to the Current User. That example doesn't store the user roles in the document fields, as is done in the following example.
For the budget scenario in this section, perform the following steps to create the roles, users, and budget collection:
Create the users
Create users named John and Jane with the required roles. Replace the test database with your database name.
db.createUser( { user: "John", pwd: "jn008", roles: [ { role: "Marketing", db: "test" }, { role: "Development", db: "test" }, { role: "Operations", db: "test" }, { role: "read", db: "test" } ] } ) db.createUser( { user: "Jane", pwd: "je009", roles: [ { role: "Sales", db: "test" }, { role: "Operations", db: "test" }, { role: "read", db: "test" } ] } )
Create the collection
Run:
db.budget.insertMany( [ { _id: 0, allowedRoles: [ "Marketing" ], comment: "For marketing team", yearlyBudget: 15000 }, { _id: 1, allowedRoles: [ "Sales" ], comment: "For sales team", yearlyBudget: 17000, salesEventsBudget: 1000 }, { _id: 2, allowedRoles: [ "Operations" ], comment: "For operations team", yearlyBudget: 19000, cloudBudget: 12000 }, { _id: 3, allowedRoles: [ "Development" ], comment: "For development team", yearlyBudget: 27000 } ] )
Perform the following steps to create a view and retrieve the documents accessible to John:
Create the view
To use a system variable, add $$ to the start of the variable name. Specify the USER_ROLES system variable as $$USER_ROLES.
Run:
db.createView( "budgetView", "budget", [ { $match: { $expr: { $not: { $eq: [ { $setIntersection: [ "$allowedRoles", "$$USER_ROLES.role" ] }, [] ] } } } } ] )
If you cannot create the view, ensure you log in as a user with the privilege to create a view.
The previous example returns the documents from the budget collection that match at least one of the roles that the user who runs the example has. To do that, the example uses $setIntersection to return documents where the intersection between the budget document allowedRoles field and the set of user roles from $$USER_ROLES is not empty.
Examine the documents
John has the Marketing, Operations, and Development roles, and sees these documents:
[ { _id: 0, allowedRoles: [ 'Marketing' ], comment: 'For marketing team', yearlyBudget: 15000 }, { _id: 2, allowedRoles: [ 'Operations' ], comment: 'For operations team', yearlyBudget: 19000, cloudBudget: 12000 }, { _id: 3, allowedRoles: [ 'Development' ], comment: 'For development team', yearlyBudget: 27000 } ]
Perform the following steps to retrieve the documents accessible to Jane:
Examine the documents
Jane has the Sales and Operations roles, and sees these documents:
[ { _id: 1, allowedRoles: [ 'Sales' ], comment: 'For sales team', yearlyBudget: 17000, salesEventsBudget: 1000 }, { _id: 2, allowedRoles: [ 'Operations' ], comment: 'For operations team', yearlyBudget: 19000, cloudBudget: 12000 } ]
Note
On a sharded cluster, a query can be run on a shard by another server node on behalf of the user. In those queries, USER_ROLES is still populated with the roles for the user.
Roles with the Same Name in Multiple Databases
Multiple databases can have roles with the same name. If you create a view and reference a specific role in the view, you should either specify both the db database name field and the role field, or specify the _id field that contains the database name and the role.
The following example returns the roles assigned to Jane, who has roles with different names. The example returns the _id, role, and db database name:
Behavior
Aggregation Optimizations
When you query a view:
Query
filter,projection,sort,skip,limit, and other operations fordb.collection.find()are converted to the equivalent aggregation pipeline stages.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.
The aggregation pipeline optimizer reshapes the view aggregation pipeline stages to improve performance without changing the query results.
Resource Locking
db.createView() obtains an exclusive lock on the specified collection or view for the duration of the operation. All subsequent operations on the collection must wait until db.createView() releases the lock. db.createView() typically holds this lock for a short time.
Creating a view requires obtaining an additional exclusive lock on the system.views collection in the database. This lock blocks creation or modification of views in the database until the command completes.