MongoDB 使用手册 - 视图(View)
MongoDB 视图(View)是一个可查询对象,其内容由 其他集合或视图上的聚合管道定义。MongoDB 不会将视图内容保存到磁盘。当客户端查询视图时,视图的内容是按需计算的。MongoDB 可以要求客户端 具有查询视图的权限。MongoDB 不支持针对视图的写操作。
例如,您可以:
- 创建有关
exclude
任何私人或个人信息 (PII) 的员工数据集合的视图。应用程序可以在视图中查询不包含任何 PII 的员工数据。 - 在收集的传感器数据集合上创建一个视图,以
add
计算字段和指标。应用程序可以使用简单的查找操作来查询数据。 - 创建一个视图,其中
joins
两个集合分别包含库存和订单历史记录。应用程序可以在不管理或了解底层复杂管道的情况下查询连接的数据。
当客户端查询视图时,MongoDB 将客户端查询附加到底层管道,并将该组合管道的结果返回给客户端。MongoDB 可以将 聚合管道优化应用于组合管道。
以下页面讨论视图。有关按需物化视图的讨论,请参阅按需物化视图 。
创建视图
创建或定义视图:
- 使用db.createCollection()方法或 create命令:
db.createCollection(
"<viewName>",
{
"viewOn" : "<source>",
"pipeline" : [<pipeline>],
"collation" : { <collation> }
}
)
- 使用db.createView()方法:
db.createView(
"<viewName>",
"<source>",
[<pipeline>],
{
"collation" : { <collation> }
}
)
您必须在与源集合相同的数据库中创建视图。
- 视图定义pipeline不能包含merge阶段。如果视图定义包括嵌套管道(例如视图定义包括 facet阶段),则此限制也适用于嵌套管道。
行为
视图表现出以下行为:
只读
视图是只读的;视图上的写操作会出错。
以下读取操作可以支持视图:
- db.collection.find()
- db.collection.findOne()
- db.collection.aggregate()
- db.collection.countDocuments()
- db.collection.estimatedDocumentCount()
- db.collection.count()
- db.collection.distinct()
索引使用和排序操作
视图使用基础集合的索引。
由于索引位于基础集合上,因此您无法直接在视图上创建、删除或重新构建索引,也无法获取视图上的索引列表。
$natural
从 MongoDB 4.4 开始,您可以在视图上运行find
命令时指定排序。MongoDB 的早期版本不支持$natural
对视图进行排序。
视图的底层聚合管道受限于 100 兆字节的内存限制,用于阻塞排序和阻塞组操作。从 MongoDB 4.4 开始,您可以在视图上发出 find
命令 allowDiskUse: true
以允许 MongoDB 使用临时文件来阻止排序和分组操作。
在 MongoDB 4.4 之前,只有aggregate命令接受该 allowDiskUse
选项。
有关阻止排序操作内存限制的更多信息,请参阅排序操作。
投影限制
- $
- $elemMatch
- $slice
- $meta
不可变名称
您不能重命名视图。
视图创建
-
视图是在读取操作期间按需计算的,MongoDB 对视图执行读取操作作为底层聚合管道的一部分。因此,视图不支持以下操作:
- db.collection.mapReduce(),
$text
运算符,因为$text
聚合中的操作仅对第一阶段有效,- $geoNear流水线阶段。
-
如果用于创建视图的聚合管道抑制了该 _id字段,则视图中的文档没有该_id字段。
当您查询视图时:
- 查询
filter
,projection
,sort
,skip
,limit
和其他操作db.collection.find()
被转换为等效的聚合管道阶段 - 转换后的聚合管道阶段将添加到 视图的聚合管道的末尾。这不会修改视图的底层管道,它是在您创建视图时设置的。
- 聚合管道优化器重塑视图聚合管道阶段以提高性能。这不会更改查询结果。
分片视图
如果视图的底层集合是分片的,则视图被认为是分片的。因此,不能在$lookup
和 $graphLookup
操作中为 from
字段指定分片视图。
视图和校对
您可以在创建时为视图指定默认排序规则。如果未指定排序规则,则视图的默认排序规则是“simple”二进制比较排序规则。也就是说,视图不继承集合的默认排序规则。
视图上的字符串比较使用视图的默认排序规则。尝试更改或覆盖视图的默认排序规则的操作将失败并出现错误。
如果从另一个视图创建视图,则不能指定与源视图的排序规则不同的排序规则。
如果执行涉及多个视图的聚合,例如 $lookup
或 $graphLookup
,则视图必须具有相同的比对规则。
公众视野定义
列出集合的操作,例如 db.getCollectionInfos()
和 db.getCollectionNames()
,在其输出中包含视图。
视图定义是公开的;即视图上
db.getCollectionInfos()
的explain
操作将包括定义视图的管道。因此,请避免在视图定义中直接引用敏感字段和值。
删除视图
要删除视图,请在视图上使用 db.collection.drop()
方法。
修改视图
您可以通过删除并重新创建视图或使用 collMod
命令来修改视图。
支持的操作
以下操作提供对视图的支持,但本页中提到的限制除外:
示例
创建 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" }
}
)
以下示例查询视图。为清楚起见,该 $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
使用在两个集合上创建视图然后对视图运行查询通常很方便。应用程序可以查询视图,而无需构建或维护复杂的管道。
创建两个样本集合,inventory
并且 orders
:
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 }
] )
创建一个组合来自每个集合的元素的视图:
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
视图基于集合 orders
。
$lookup
使用集合 orders
中的 prodId
字段 来“join” 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 }
]
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构