创建和查询视图
在此页面上
要创建视图,请使用以下方法之一:
要在 MongoDB Atlas 用户界面中创建视图,您必须使用物化视图。如需了解详情,请参阅在 MongoDB Atlas 用户界面中创建物化视图。
重要
视图名称包含在集合列表输出中
列出集合的操作,例如 db.getCollectionInfos()
和 db.getCollectionNames()
,在其输出中包含视图。
视图定义是公开的;即视图上的 db.getCollectionInfos()
和 explain
操作将包括定义视图的管道。因此,应避免在视图定义中直接引用敏感字段和值。
db.createCollection()
语法
db.createCollection( "<viewName>", { "viewOn" : "<source>", "pipeline" : [<pipeline>], "collation" : { <collation> } } )
db.createView()
语法
db.createView( "<viewName>", "<source>", [<pipeline>], { "collation" : { <collation> } } )
限制
您必须在与源集合相同的数据库中创建视图。
视图定义
pipeline
不能包含$out
或$merge
阶段。这一限制也适用于嵌入式管道,例如在$lookup
或$facet
阶段中使用的管道。视图一旦创建便无法重命名。
不支持的操作
某些操作不适用于视图:
$text
操作符,因为聚合中的$text
只对第一阶段有效。正在重新命名视图。
有关详细信息,请参阅视图支持的操作。
示例
第一个示例使用学生数据填充集合,并创建了一个用于查询该数据的视图。
填充集合
创建一个用于此示例的 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 }, ] )
使用 db.createView() 创建视图
使用 db.createView()
创建仅限一年级学生的视图:
db.createView( "firstYears", "students", [ { $match: { year: 1 } } ] )
在示例中:
firstYears
是新视图的名称。students
是视图所依据的集合。$match
是一个聚合表达式,它会与students
集合中的一年级学生进行匹配。
查询视图
此示例查询视图:
db.firstYears.find({}, { _id: 0 } )
以下输出仅包含具有一年级学生数据的文档。{ _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 } ]
使用 db.createCollection() 创建视图
使用 db.createCollection()
方法可以创建具有特定选项的集合或视图。
以下示例将创建一个 graduateStudents
视图。该视图仅包含由 $match
阶段选择的文档。排序规则设置(可选)决定了排序顺序。
db.createCollection( "graduateStudents", { viewOn: "students", pipeline: [ { $match: { $expr: { $gt: [ "$year", 4 ] } } } ], collation: { locale: "en", caseFirst: "upper" } } )
注意
排序规则行为
您可以在创建视图时为其指定默认排序规则。如果未指定排序规则,则视图的默认排序规则是“简单”二进制比较排序规则。也就是说,视图不会继承集合的默认排序规则。
视图上的字符串比较使用的是视图的默认排序规则。尝试更改或覆盖视图默认排序规则的操作会失败并报错。
如果从另一个视图创建视图,则无法指定与源视图不同的排序规则。
如果执行的聚合涉及多个视图,例如使用
$lookup
或$graphLookup
,则这些视图必须采用相同的排序规则。
查询视图
以下示例将查询该视图。为清晰起见,$unset
阶段会从输出中删除 _id
字段。
db.graduateStudents.aggregate( [ { $sort: { name: 1 } }, { $unset: [ "_id" ] } ] )
对输出进行排序时,$sort
阶段使用排序规则对小写字母前的大写字母进行排序。
[ { sID: 18020, name: 'Harley', year: 5, score: 2.8 }, { sID: 17301, name: 'harley', year: 6, score: 3.1 } ]
检索授予当前用户的角色相关的医疗信息
从 MongoDB 7.0 开始,您可以使用新的 USER_ROLES
系统变量来返回用户角色。
本节中的示例显示了用户对包含医疗信息的集合中的字段具有有限访问权限。该示例使用一个视图,该视图从 USER_ROLES
系统变量中读取当前用户角色,并根据相应角色隐藏字段。
该示例创建这些用户:
James
具有可以访问creditCard
字段的Billing
角色。Michelle
具有可以访问diagnosisCode
字段的Provider
角色。
执行以下步骤来创建角色、用户、集合和视图:
创建视图
要使用系统变量,请将$$
添加到变量名称的开头。将USER_ROLES
系统变量指定为$$USER_ROLES
。
该视图将从 USER_ROLES
系统变量读取当前用户角色,并按角色隐藏字段。
运行:
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" } } } } ] )
视图示例:
执行以下步骤来检索 James
可以访问的信息:
执行以下步骤来检索 Michelle
可以访问的信息:
检索授予当前用户的角色相关的预算文档
从 MongoDB 7.0 开始,您可以使用新的 USER_ROLES
系统变量来返回用户角色。
本部分的场景显示了具有各种角色的用户,而这些用户对包含预算信息的集合中的文档具有有限访问权限。
该场景显示了 USER_ROLES
的一种可能用途。budget
集合包含带有名为 allowedRoles
字段的文档。正如以下场景所示,您可以编写查询将 allowedRoles
字段中找到的用户角色与 USER_ROLES
系统变量返回的角色进行比较。
注意
有关另一个 USER_ROLES
示例场景,请参阅 检索授予当前用户角色的医疗信息。该示例不会将用户角色存储在文档字段中,如以下示例所示。
对于本部分中的预算方案,请执行以下步骤来创建角色、用户和 budget
集合:
创建用户
创建名为 John
和 Jane
的用户,并赋予所需角色。将 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" } ] } )
创建集合
运行:
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 } ] )
执行以下步骤以创建视图并检索 John
可以访问的文档:
创建视图
要使用系统变量,请将$$
添加到变量名称的开头。将USER_ROLES
系统变量指定为$$USER_ROLES
。
运行:
db.createView( "budgetView", "budget", [ { $match: { $expr: { $not: { $eq: [ { $setIntersection: [ "$allowedRoles", "$$USER_ROLES.role" ] }, [] ] } } } } ] )
如果无法创建视图,请确保您以拥有视图创建权限的用户身份登录。
上一示例从budget
集合中返回至少与运行该示例的用户所具有的角色之一匹配的文档。为此,该示例使用$setIntersection
返回文档,其中budget
文档allowedRoles
字段与$$USER_ROLES
的用户角色集之间的交集不为空。
检查文档
John
具有Marketing
、Operations
和Development
角色,且能看到以下文档:
[ { _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 } ]
执行以下步骤来获取 Jane 可以访问的文档:
检查文档
Jane
具有 Sales
和 Operations
角色,且能看到以下文档:
[ { _id: 1, allowedRoles: [ 'Sales' ], comment: 'For sales team', yearlyBudget: 17000, salesEventsBudget: 1000 }, { _id: 2, allowedRoles: [ 'Operations' ], comment: 'For operations team', yearlyBudget: 19000, cloudBudget: 12000 } ]
注意
在分片集群上,查询可以由另一个服务器节点代表用户在分片上运行。在这些查询中,USER_ROLES
仍填充用户的角色。
多个数据库中具有相同名称的角色
多个数据库可以具有同名的角色。如果您创建了一个视图,并在该视图中引用了一个特定角色,则应同时指定 db
数据库名称字段和 role
字段,或指定包含数据库名称和角色的 _id
字段。
以下示例将返回分配给 Jane
的角色,此用户拥有不同名称的角色。该示例将返回 _id
、role
和 db
数据库名称:
行为
以下各部分介绍了视图创建和查询的行为。
聚合优化
当您查询视图时:
查询
filter
、projection
、sort
、skip
、limit
和db.collection.find()
的其他操作会转换为等效的聚合管道阶段。MongoDB 将客户端查询附加到底层管道,并将组合管道的结果返回给客户端。MongoDB 可能会将聚合管道优化应用于组合管道。
聚合管道优化器可重塑视图的聚合管道阶段以提高性能。优化操作不会更改查询结果。
资源锁定
db.createView()
在操作期间获得指定集合或视图的独占锁。对集合的所有后续操作都必须等到 db.createView()
释放该锁为止。db.createView()
通常会短暂占用该锁。
创建视图需获得数据库中 system.views
集合的额外独占锁。此锁会阻止创建或修改数据库中的视图,直到命令完成。