Docs HomeMongoDB Manual

Create and Query a View创建和查询视图

To create a view, use db.createCollection() or db.createView().要创建视图,请使用db.createCollection()db.createView()

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.列出集合的操作,如db.getCollectionInfos()db.getCollectionNames(),在其输出中包含视图。

The view definition is public; i.e. db.getCollectionInfos() and explain operations on the view will include the pipeline that defines the view. 视图定义是公开的;db.getCollectionInfos()explain对视图的操作将包括定义视图的管道。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.您必须在与源集合相同的数据库中创建视图。
  • A view definition pipeline cannot include the $out or the $merge stage. 视图定义pipeline不能包含$out$merge阶段。This restriction also applies to embedded pipelines, such as pipelines used in $lookup or $facet stages.此限制也适用于嵌入式管道,例如$lookup$facet阶段中使用的管道。
  • You cannot rename a view once it is created.创建视图后,不能对其进行重命名。

Unsupported Operations不支持的操作

Some operations are not available with views:某些操作不可用于视图:

  • db.collection.mapReduce().
  • $text operator, since $text operation in aggregation is valid only for the first stage.$text运算符,因为聚合中的$text操作仅对第一阶段有效。
  • $geoNear pipeline stage.管道阶段。
  • Renaming a view.重命名视图。

For more information, see Supported Operations for Views.有关详细信息,请参阅支持的视图操作

Examples实例

The first example populates a collection with student data and creates a view to query the data.第一个示例用学生数据填充集合,并创建一个视图来查询数据。

Populate the Collection填充集合

Create a students collection to use for this example:创建students集合以用于此示例:

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()创建视图

Use db.createView() to create a view that is limited to first year students:使用db.createView()创建一个仅限一年级学生使用的视图:

db.createView(
"firstYears",
"students",
[ { $match: { year: 1 } } ]
)

In the example:在示例中:

  • firstYears is the name of the new view.是新视图的名称。
  • students is the collection the view is based on.是视图所基于的集合。
  • $match is an aggregation expression that matches first year students in the students collection.是一个聚合表达式,与students集合中的一年级学生相匹配。

Query the View查询视图

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.{ _id: 0 }投影抑制输出中的_id字段。

[
{ 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 Query and Projection Operators operators:视图上的操作不支持以下查询运算符和投影运算符

Use db.createCollection() to Create a View使用db.createCollection()创建视图

The db.createCollection() method allows you to create a collection or a view with specific options.db.createCollection()方法允许您创建具有特定选项的集合或视图。

The following example creates a graduateStudents view. 以下示例创建了一个graduateStudents视图。The view only contains documents selected by the $match stage. 该视图仅包含由$match阶段选择的文档。The optional collation setting determines the sort order.可选的排序规则设置确定排序顺序。

db.createCollection(
"graduateStudents",
{
viewOn: "students",
pipeline: [ { $match: { $expr: { $gt: [ "$year", 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. 如果未指定排序规则,则视图的默认排序规则是"simple"二进制比较排序规则。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 $lookup or $graphLookup, the views must have the same collation.如果执行涉及多个视图的聚合,例如使用$lookup$graphLookup,则这些视图必须具有相同的排序规则

Query the View查询视图

The following example queries the view. 以下示例查询视图。The $unset stage removes the _id field from the output for clarity.为了清楚起见,$unset阶段从输出中删除了_id字段。

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.对输出进行排序时,$sort阶段使用排序规则将大写字母排在小写字母之前。

[
{ 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.从MongoDB 7.0开始,您可以使用新的USER_ROLES系统变量来返回用户角色。

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.该示例使用的视图从USER_ROLES系统变量中读取当前用户角色,并隐藏基于角色的字段。

The example creates these users:该示例创建了以下用户:

  • James with a Billing role who can access a creditCard field.James具有Billing角色,可以访问creditCard字段。
  • Michelle with a Provider role who can access a diagnosisCode field.Michelle具有Provider角色,可以访问diagnosisCode字段。

Perform the following steps to create the roles, users, collection, and view:执行以下步骤以创建角色、用户、集合和视图:

1

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: [ ] } )
2

Create the users创建用户

Create users named James and Michelle with the required roles. 创建具有所需角色的名为JamesMichelle的用户。Replace the test database with your database name.test数据库替换为您的数据库名称。

db.createUser( {
user: "James",
pwd: "js008",
roles: [
{ role: "Billing", db: "test" }
]
} )

db.createUser( {
user: "Michelle",
pwd: "me009",
roles: [
{ role: "Provider", db: "test" }
]
} )
3

Create the collection创建集合

Run:运行:

db.medical.insertMany( [
{
_id: 0,
patientName: "Jack Jones",
diagnosisCode: "CAS 17",
creditCard: "1234-5678-9012-3456"
},
{
_id: 1,
patientName: "Mary Smith",
diagnosisCode: "ACH 01",
creditCard: "6541-7534-9637-3456"
}
] )
4

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.USER_ROLES系统变量指定为$$USER_ROLES

The view reads the current user roles from the USER_ROLES system variable and hides fields based on the roles.该视图从USER_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 diagnosisCode field for a user with the Provider role.包括具有Provider角色的用户的diagnosisCode字段。
  • includes the creditCard field for a user with the Billing role.包括具有Billing角色的用户的creditCard字段。
  • uses $set pipeline stages and $$REMOVE to hide fields based on whether the user who queries the view has the matching role returned in $$USER_ROLES.role.使用$set管道阶段和$$REMOVE根据查询视图的用户是否具有$$USER_ROLES.role中返回的匹配角色来隐藏字段。

Perform the following steps to retrieve the information accessible to James:执行以下步骤以检索James可访问的信息:

1

Log in as James以James身份登录

Run:运行:

db.auth( "James", "js008" )
2

Retrieve the documents检索文档

Run:运行:

db.medicalView.find()
3

Examine the documents检查文件

James has the Billing role and sees the following documents, which include the creditCard field but not the diagnosisCode field:James具有Billing角色,并查看以下文档,其中包括creditCard字段,但不包括diagnosisCode字段:

[
{
_id: 0, patientName: 'Jack Jones',
creditCard: '1234-5678-9012-3456'
},
{
_id: 1, patientName: 'Mary Smith',
creditCard: '6541-7534-9637-3456'
}
]

Perform the following steps to retrieve the information accessible to Michelle:执行以下步骤以检索Michelle可访问的信息:

1

Log in as Michelle以Michelle身份登录

Run:运行:

db.auth( "Michelle", "me009" )
2

Retrieve the documents检索文档

Run:运行:

db.medicalView.find()
3

Examine the documents检查文件

Michelle has the Provider role and sees the following documents, which include the diagnosisCode field but not the creditCard field:Michelle具有Provider角色,并查看以下文档,其中包括diagnosisCode字段,但不包括creditCard字段:

[
{ _id: 0, patientName: 'Jack Jones',
diagnosisCode: 'CAS 17' },
{ _id: 1, patientName: 'Mary Smith',
diagnosisCode: 'ACH 01' }
]

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.从MongoDB 7.0开始,您可以使用新的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. 该场景显示了USER_ROLES的一种可能用途。The budget collection contains documents with a field named allowedRoles. budget集合包含一个名为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.正如您在下面的场景中看到的那样,您可以编写查询,将allowedRoles字段中的用户角色与USER_ROLES系统变量返回的角色进行比较。

Note

For another USER_ROLES example scenario, see Retrieve Medical Information for Roles Granted to the Current User. 有关另一个USER_ROLES示例场景,请参阅检索授予当前用户的角色的医疗信息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:对于本节中的预算方案,请执行以下步骤来创建角色、用户和budget集合:

1

Create the roles创建角色

Run:运行:

db.createRole( { role: "Marketing", roles: [], privileges: [] } )
db.createRole( { role: "Sales", roles: [], privileges: [] } )
db.createRole( { role: "Development", roles: [], privileges: [] } )
db.createRole( { role: "Operations", roles: [], privileges: [] } )
2

Create the users创建用户

Create users named John and Jane with the required roles. 创建具有所需角色的名为JohnJane的用户。Replace the test database with your database name.test数据库替换为您的数据库名称。

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" }
]
} )
3

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:执行以下步骤以创建视图并检索John可访问的文档:

1

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.USER_ROLES系统变量指定为$$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. 上一个示例返回budget集合中与运行该示例的用户所具有的至少一个角色相匹配的文档。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.为此,该示例使用$setIntersection返回budget文档allowedRoles字段和$$USER_ROLES中的用户角色集之间的交集不为空的文档。

2

Log in as John以John身份登录

Run:运行:

db.auth( "John", "jn008" )
3

Retrieve the documents检索文档

Run:运行:

db.budgetView.find()
4

Examine the documents检查文件

John has the Marketing, Operations, and Development roles, and sees these documents:John具有MarketingOperationsDevelopment角色,并查看以下文档:

[
{
_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:执行以下步骤以检索Jane可访问的文档:

1

Log in as JaneJane身份登录

Run:运行:

db.auth( "Jane", "je009" )
2

Retrieve the documents检索文档

Run:运行:

db.budgetView.find()
3

Examine the documents检查文件

Jane has the Sales and Operations roles, and sees these documents:Jane具有SalesOperations角色,并查看以下文档:

[
{
_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.在这些查询中,USER_ROLES仍然填充有用户的角色。

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.如果创建视图并引用视图中的特定角色,则应同时指定db数据库名称字段和role字段,或者指定包含数据库名称和角色的_id字段。

The following example returns the roles assigned to Jane, who has roles with different names. 以下示例返回分配给Jane的角色,Jane拥有不同名称的角色。The example returns the _id, role, and db database name:此示例返回_idroledb名称:

1

Log in as JaneJane身份登录

Run:运行:

db.auth( "Jane", "je009" )
2

Retrieve the documents检索文档

Run:运行:

db.budget.findOne( {}, { myRoles: "$$USER_ROLES" } )
3

Examine the documents检查文件

Example output, which shows the _id, role, and db database name in the myRoles array:示例输出,显示myRoles数组中的_idroledb数据库名称:

{
_id: 0,
myRoles: [
{ _id: 'test.Operations', role: 'Operations', db: 'test' },
{ _id: 'test.Sales', role: 'Sales', db: 'test' },
{ _id: 'test.read', role: 'read', db: 'test' }
]
}

Behavior行为

The following sections describe the behaviors of view creation and queries.以下部分介绍了视图创建和查询的行为。

Aggregation Optimizations聚合优化

When you query a view:查询视图时:

  • Query filter, projection, sort, skip, limit, and other operations for db.collection.find() are converted to the equivalent aggregation pipeline stages.db.collection.find()的查询filterprojectionsortskiplimit和其他操作将转换为等效的聚合管道阶段。
  • MongoDB appends the client query to the underlying pipeline and returns the results of that combined pipeline to the client. MongoDB将客户端查询附加到底层管道,并将组合管道的结果返回给客户端。MongoDB may apply aggregation pipeline optimizations to the combined pipeline.MongoDB可能会对合并后的管道进行聚合管道优化
  • The aggregation pipeline optimizer reshapes the view aggregation pipeline stages to improve performance. 聚合管道优化器重新调整视图聚合管道阶段以提高性能。The optimization does not change 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()释放锁。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. 创建视图需要对数据库中的system.views集合获取额外的独占锁。This lock blocks creation or modification of views in the database until the command completes.此锁会阻止在数据库中创建或修改视图,直到命令完成。