Docs 菜单
Docs 主页
/
MongoDB Manual
/ /

视图

在此页面上

  • 创建视图
  • 行为
  • 删除视图
  • 修改视图
  • 支持的操作
  • 示例

MongoDB视图是一个可查询对象,其内容由其他集合或视图上的 聚合管道定义。 MongoDB不会将视图内容持久保存到磁盘。当客户端查询视图时,会按需计算视图的内容。 MongoDB可以要求客户端拥有查询视图的权限。 MongoDB不支持对视图执行写入操作。

例如,您可以:

当客户端查询视图时, MongoDB会将客户端查询附加到根本的管道,并将组合管道的结果返回给客户端。 MongoDB可能会将聚合管道优化应用组合管道。

注意

以下页面将讨论视图。 有关按需物化视图的讨论,请参阅按需物化视图

要创建或定义视图,请执行以下操作:

  • 使用db.createCollection()方法或create命令:

    db.createCollection(
    "<viewName>",
    {
    "viewOn" : "<source>",
    "pipeline" : [<pipeline>],
    "collation" : { <collation> }
    }
    )
  • 使用db.createView()方法:

    db.createView(
    "<viewName>",
    "<source>",
    [<pipeline>],
    {
    "collation" : { <collation> }
    }
    )

注意

— 必须在与源collection相同的数据库中创建视图。

  • 视图定义pipeline不能包含$out$merge阶段。 如果视图定义包含嵌套管道(例如视图定义包含$lookup$facet阶段),则此限制也适用于嵌套管道。

警告

请勿尝试创建名称为system.profile的时间序列集合或视图,否则 MongoDB Server 会崩溃。

视图表现出以下行为:

视图为只读;对视图进行写入操作会出错。

以下读取操作可以支持视图:

  • 视图使用底层集合的索引。

  • 由于索引位于底层collection上,因此您无法直接在视图上创建、删除或重新构建索引,也无法获取视图上的索引列表。

  • 从 MongoDB 4.4 开始,对视图运行 命令时,可以指定$natural find排序。以前版本的 MongoDB 不支持对视图进行$natural排序。

  • 对于阻塞排序和阻塞分组操作,视图的底层聚合管道受到 100 MB 内存限制。 从 MongoDB 4.4 开始,您可以对视图发出带有allowDiskUse: truefind命令,以允许 MongoDB 使用临时文件进行阻塞排序和分组操作。

    在 MongoDB 4.4 之前,只有aggregate命令接受allowDiskUse选项。

    提示

    另请参阅:

    有关阻塞排序操作内存限制的更多信息,请参阅排序操作。

视图上的find()操作不支持以下投影操作符:

您无法重命名视图

  • 视图是在读取操作期间按需计算的,MongoDB 将对视图执行读取操作作为底层聚合管道的一部分。 因此,视图不支持以下操作:

  • 如果用于创建视图的聚合管道抑制_id字段,则视图中的文档没有_id字段。

查询视图时,:

  • 查询 filterprojectionsortskiplimitdb.collection.find() 的其他操作会转换为等效的聚合管道阶段。

  • 转换后的聚合管道阶段将添加到视图的聚合管道的末尾。 这不会修改视图的底层管道,该管道是在创建视图时设置的。

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

如果视图的底层集合已分片,则视图也被视为已分片。 因此,您无法在$lookup$graphLookup操作中为from字段指定分片视图。

  • 您可以在创建视图时为其指定默认排序规则。如果未指定排序规则,则视图的默认排序规则是“简单”二进制比较排序规则。也就是说,视图不会继承集合的默认排序规则。

  • 视图上的字符串比较使用的是视图的默认排序规则。尝试更改或覆盖视图默认排序规则的操作会失败并报错。

  • 如果从另一个视图创建视图,则无法指定与源视图不同的排序规则。

  • 如果执行的聚合涉及多个视图,例如使用 $lookup$graphLookup ,则这些视图必须采用相同的排序规则

视图不维护集合更改的时间戳,也不支持时间点或快照读取隔离。

列出collection的操作(例如db.getCollectionInfos()db.getCollectionNames() )在其输出中包含视图。

重要

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

要删除视图,请对视图执行 db.collection.drop() 方法。

您可以通过删除并重新创建视图或使用collMod命令来修改视图。

以下操作为视图提供支持,但本页提到的限制除外:

命令
方法

创建要在以下示例中使用的studentscollection:

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 }
]

使用 db.createCollection() 方法可以创建具有特定选项的集合或视图。

以下示例将创建一个 graduateStudents 视图。该视图仅包含由 $match 阶段选择的文档。排序规则设置(可选)决定了排序顺序。

db.createCollection(
"graduateStudents",
{
viewOn: "students",
pipeline: [ { $match: { $expr: { $gt: [ "$year", 4 ] } } } ],
collation: { locale: "en", caseFirst: "upper" }
}
)

以下示例将查询该视图。为清晰起见,$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 }
]

使用$lookup创建两个集合的视图,然后对该视图运行查询通常很方便。 应用程序可以查询视图,而无需构建或维护复杂的管道。

创建两个样本集合 inventoryorders

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

创建一个视图,将每个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" }
] )

在示例中:

  • db.createView()创建sales视图。

  • sales视图基于orderscollection。

  • $lookup 阶段使用 orders 集合中的 prodId 字段来“连接” inventory 集合中具有匹配 prodId 字段的文档。

  • 匹配的文档将作为数组添加到 inventoryDocs 字段中。

  • $project 阶段选择可用字段的子集。

  • $unwind 阶段会将 price 字段从数组转换为标量值。

sales 视图中的文档包括:

{ 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 }

要查找每种产品的总销售量,请查询视图:

db.sales.aggregate( [
{
$group:
{
_id: "$prodId",
amountSold: { $sum: { $multiply: [ "$price", "$numPurchased" ] } }
}
}
] )

输出见下:

[
{ _id: 100, amountSold: 600 },
{ _id: 103, amountSold: 1105 },
{ _id: 101, amountSold: 150 },
{ _id: 102, amountSold: 90 }
]

后退

数据库和collection