文档菜单
文档首页
/
MongoDB 手册
/ / /

创建和查询视图

本页内容

  • db.createCollection() 语法
  • db.createView() 语法
  • 限制
  • 不支持的运算
  • 示例
  • 填充集合
  • 使用 db.createView() 创建视图
  • 使用 db.createCollection() 创建视图
  • 检索当前用户所授权角色的医疗信息
  • 检索当前用户所授权角色的预算文档
  • 多个数据库中同名角色
  • 行为
  • 聚合优化
  • 资源锁定

要创建视图,可以使用以下方法之一

要在 MongoDB Atlas UI 中创建视图,必须使用物化视图。有关更多信息,请参阅在 MongoDB Atlas UI 中创建物化视图。

重要

视图名称包含在集合列表输出中

列出集合的操作,如 db.getCollectionInfos()db.getCollectionNames(),其输出包括视图。

视图定义是公开的;即 db.getCollectionInfos()explain 操作将包括定义视图的管道。因此,避免在视图定义中直接引用敏感字段和值。

db.createCollection(
"<viewName>",
{
"viewOn" : "<source>",
"pipeline" : [<pipeline>],
"collation" : { <collation> }
}
)
db.createView(
"<viewName>",
"<source>",
[<pipeline>],
{
"collation" : { <collation> }
}
)
  • 您必须在与源集合相同的数据库中创建视图。

  • 视图定义中的 管道 不能包含 $out$merge 阶段。此限制也适用于嵌入的管道,例如在 $lookup$facet 阶段中使用的管道。

  • 一旦创建视图,就不能重命名它。

某些操作在视图中不可用

有关更多信息,请参阅 视图支持的操作。

第一个示例使用学生数据填充一个集合,并创建一个视图来查询数据。

创建一个用于此示例的 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(
"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 }
]

注意

投影限制

find() 操作在视图上不支持以下 查询和投影操作符

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,具有 Billing 角色,可以访问 creditCard 字段。

  • Michelle,具有 Provider 角色,可以访问 diagnosisCode 字段。

执行以下步骤来创建角色、用户、集合和视图

1

运行

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

创建名为 JamesMichelle 的用户,并赋予所需的角色。将 test 数据库替换为您的数据库名称。

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

运行

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

要使用系统变量,在变量名称前添加 $$。将 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"
}
}
}
} ]
)

视图示例

  • 包括为具有 Provider 角色的用户提供的 diagnosisCode 字段。

  • 包括为具有 Billing 角色的用户提供的 creditCard 字段。

  • 使用 $set 管道阶段和 $$REMOVE 来根据查询视图的用户是否具有在 $$USER_ROLES.role 返回的匹配角色来隐藏字段。

执行以下步骤以检索 James 可访问的信息

1

运行

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

运行

db.medicalView.find()
3

James 具有 Billing 角色,并看到以下文档,这些文档包含 creditCard 字段但不包含 diagnosisCode 字段。

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

执行以下步骤以检索 Michelle 可访问的信息

1

运行

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

运行

db.medicalView.find()
3

Michelle拥有提供者角色,可以看到以下文档,这些文档包含诊断代码字段,但不包含信用卡字段

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

从 MongoDB 7.0 版本开始,您可以使用新的 USER_ROLES 系统变量来返回用户 角色。

本节中的场景展示了具有不同角色且对包含预算信息的集合中文档有限访问权限的用户。

该场景展示了 USER_ROLES 的一种可能用途。budget 集合包含具有名为 allowedRoles 字段的文档。正如以下场景所示,您可以编写查询,将 allowedRoles 字段中找到的用户角色与 USER_ROLES 系统变量返回的角色进行比较。

注意

有关另一个 USER_ROLES 示例场景,请参阅检索当前用户所授权角色的医疗信息。该示例与以下示例不同,因为它没有在文档字段中存储用户角色。

对于本节中的预算场景,请执行以下步骤以创建角色、用户和 budget 集合

1

运行

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

创建名为 JohnJane 的用户,并赋予所需角色。将 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

运行

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 可访问的文档。

1

要使用系统变量,在变量名称前添加 $$。将 USER_ROLES 系统变量指定为 $$USER_ROLES

运行

db.createView(
"budgetView", "budget",
[ {
$match: {
$expr: {
$not: {
$eq: [ { $setIntersection: [ "$allowedRoles", "$$USER_ROLES.role" ] }, [] ]
}
}
}
} ]
)

如果您无法创建视图,请确保您以具有创建视图权限的用户登录。

上一个示例返回来自 budget 集合的文档,这些文档至少匹配运行示例的用户具有的一个角色。为此,示例使用 $setIntersection 返回文档,其中 budget 文档的 allowedRoles 字段与 $$USER_ROLES 用户角色的集合之间的交集非空。

2

运行

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

运行

db.budgetView.find()
4

John 拥有 营销运营开发 角色,并查看这些文档

[
{
_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 可访问的文档

1

运行

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

运行

db.budgetView.find()
3

Jane 拥有 销售运营 角色,并可以看到这些文档

[
{
_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)和角色字段,或者指定包含数据库名称和角色的 _id 字段。

以下示例返回具有不同名称角色的 Jane 分配的角色。示例返回 _idroledb 数据库名称。

1

运行

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

运行

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

示例输出,显示了在 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' }
]
}

以下章节描述了视图创建和查询的行为。

当你查询视图时

  • 查询 filterprojectionsortskiplimit 和其他 db.collection.find() 操作被转换为等价的 聚合管道阶段。

  • MongoDB 将客户端查询追加到底层管道,并将该组合管道的结果返回给客户端。MongoDB 可能会对组合管道应用 聚合管道优化

  • 聚合管道优化器重新塑造视图聚合管道阶段以改进性能。优化不会更改查询结果。

db.createView() 在操作期间对指定的集合或视图获取独占锁。所有后续的集合操作必须等待 db.createView() 释放锁。通常 db.createView() 持有这个锁的时间很短。

创建视图需要获取对数据库中 system.views 集合的附加独占锁。此锁阻止在命令完成之前在数据库中创建或修改视图。

返回

视图