1,视图(View)
MongoDB视图是一个可查询的对象,其内容由其他集合或视图上的聚合管道定义。
MongoDB不会将视图内容持久化到磁盘。
当客户端查询视图时,视图的内容是按需计算的。
MongoDB可以要求客户端拥有查询视图的权限。
MongoDB不支持对视图进行写操作。
2,创建视图语法
db.createCollection(
"<viewName>",
{
"viewOn" : "<source>",
"pipeline" : [<pipeline>],
"collation" : { <collation> }
}
);
或
db.createView(
"<viewName>",
"<source>",
[<pipeline>],
{
"collation" : { <collation> }
}
);
ps: 必须在与源集合相同的数据库中创建视图。
3,视图特点
只读
视图是只读;对视图的写操作将出错。
支持如下只读操作:
db.collection.find()
db.collection.findOne()
db.collection.aggregate()
db.collection.countDocuments()
db.collection.estimatedDocumentCount()
db.collection.count()
db.collection.distinct()
索引使用和排序操作
视图使用基础集合的索引。
由于索引位于基础集合上,您不能直接在视图上创建、删除或重新构建索引,也不能在视图上获得索引列表
从MongoDB 4.4开始,您可以在视图上运行查找命令时指定$natural排序。MongoDB以前的版本不支持视图上的$natural排序。
视图的底层聚合管道受制于阻塞sort和阻塞group操作的100兆内存限制。从MongoDB 4.4开始,你可以在视图上发出一个allowDiskUse: true的find命令来允许MongoDB使用临时文件来阻塞sort和group操作。在MongoDB 4.4之前,只有aggregate命令接受allowDiskUse选项。
投影限制
视图上的find()操作不支持以下投影操作符:
$
$elemMatch
$slice
$meta
视图名字不变
不能重命名视图
创建视图
在读取操作期间,视图是按需计算的,MongoDB作为底层聚合管道的一部分对视图执行读取操作。因此,视图不支持以下操作:
db.collection.mapReduce()
$text操作符,因为聚合中的$text操作仅对第一阶段有效
$geoNear管道阶段
如果用于创建视图的聚合管道取消了_id字段,则视图中的文档没有_id字段。
分片视图
如果视图的基础集合被分片,则视图被认为是分片的。因此,不能在$lookup和$graphLookup操作中为from字段指定分片视图
视图和排序
可以在创建时为视图指定默认排序规则。如果没有指定排序规则,视图的默认排序规则是“simple”二进制比较排序规则。也就是说,视图不继承集合的默认排序规则。
视图上的字符串比较使用该视图的默认排序规则。试图更改或覆盖视图的默认排序规则的操作将失败并出现错误。
如果从另一个视图创建视图,则不能指定与源视图的排序规则不同的排序规则。
如果执行涉及多个视图的聚合,例如使用$lookup或$graphLookup,则视图必须具有相同的排序规则。
公共视图定义
列出集合的操作,如db.getCollectionInfos()和db.getCollectionNames(),在其输出中包括视图。
4,删除视图
db.collection.drop();
5,修改视图
可以通过删除并重新创建视图或使用collMod命令来修改视图。
6,On-Demand Materialized Views(按需实现视图)
从4.2版开始,MongoDB为聚合管道添加了$merge阶段。此阶段可以将管道结果合并到现有集合,而不是完全替换该集合。此功能允许用户创建随需应变的实现视图,其中输出集合的内容可以在每次运行管道时更新
例子数据:
db.bakesales.insertMany( [
{ date: new ISODate("2018-12-01"), item: "Cake - Chocolate", quantity: 2, amount: new NumberDecimal("60") },
{ date: new ISODate("2018-12-02"), item: "Cake - Peanut Butter", quantity: 5, amount: new NumberDecimal("90") },
{ date: new ISODate("2018-12-02"), item: "Cake - Red Velvet", quantity: 10, amount: new NumberDecimal("200") },
{ date: new ISODate("2018-12-04"), item: "Cookies - Chocolate Chip", quantity: 20, amount: new NumberDecimal("80") },
{ date: new ISODate("2018-12-04"), item: "Cake - Peanut Butter", quantity: 1, amount: new NumberDecimal("16") },
{ date: new ISODate("2018-12-05"), item: "Pie - Key Lime", quantity: 3, amount: new NumberDecimal("60") },
{ date: new ISODate("2019-01-25"), item: "Cake - Chocolate", quantity: 2, amount: new NumberDecimal("60") },
{ date: new ISODate("2019-01-25"), item: "Cake - Peanut Butter", quantity: 1, amount: new NumberDecimal("16") },
{ date: new ISODate("2019-01-26"), item: "Cake - Red Velvet", quantity: 5, amount: new NumberDecimal("100") },
{ date: new ISODate("2019-01-26"), item: "Cookies - Chocolate Chip", quantity: 12, amount: new NumberDecimal("48") },
{ date: new ISODate("2019-01-26"), item: "Cake - Carrot", quantity: 2, amount: new NumberDecimal("36") },
{ date: new ISODate("2019-01-26"), item: "Cake - Red Velvet", quantity: 5, amount: new NumberDecimal("100") },
{ date: new ISODate("2019-01-27"), item: "Pie - Chocolate Cream", quantity: 1, amount: new NumberDecimal("20") },
{ date: new ISODate("2019-01-27"), item: "Cake - Peanut Butter", quantity: 5, amount: new NumberDecimal("80") },
{ date: new ISODate("2019-01-27"), item: "Tarts - Apple", quantity: 3, amount: new NumberDecimal("12") },
{ date: new ISODate("2019-01-27"), item: "Cookies - Chocolate Chip", quantity: 12, amount: new NumberDecimal("48") },
{ date: new ISODate("2019-01-27"), item: "Cake - Carrot", quantity: 5, amount: new NumberDecimal("36") },
{ date: new ISODate("2019-01-27"), item: "Cake - Red Velvet", quantity: 5, amount: new NumberDecimal("100") },
{ date: new ISODate("2019-01-28"), item: "Cookies - Chocolate Chip", quantity: 20, amount: new NumberDecimal("80") },
{ date: new ISODate("2019-01-28"), item: "Pie - Key Lime", quantity: 3, amount: new NumberDecimal("60") },
{ date: new ISODate("2019-01-28"), item: "Cake - Red Velvet", quantity: 5, amount: new NumberDecimal("100") },
] );
1,定义实现视图
updateMonthlySales = function(startDate) {
db.bakesales.aggregate( [
{ $match: { date: { $gte: startDate } } },
{ $group: { _id: { $dateToString: { format: "%Y-%m", date: "$date" } }, sales_quantity: { $sum: "$quantity"}, sales_amount: { $sum: "$amount" } } },
{ $merge: { into: "monthlybakesales", whenMatched: "replace" } }
] );
};
说明:
$match阶段过滤数据,只处理大于或等于startDate的销售额。
$group阶段按年-月对销售信息进行分组
$merge阶段将输出写入monthlybakesales集合
根据_id字段(非分片输出集合的默认值),该阶段检查聚合结果中的文档是否与集合中的现有文档匹配:
当有匹配时(即集合中已经存在一个年-月相同的文档),该阶段将使用聚合结果中的文档替换现有文档。
当没有匹配时,stage将来自聚合结果的文档插入到集合中(不匹配时的默认行为)。
2,执行初始化
updateMonthlySales(new ISODate("1970-01-01"));
# 查询结果
db.monthlybakesales.find({}).sort({_id:1});
# 输出
{ "_id" : "2018-12", "sales_quantity" : 41, "sales_amount" : NumberDecimal("506") }
{ "_id" : "2019-01", "sales_quantity" : 86, "sales_amount" : NumberDecimal("896") }
3,刷新实现视图
# 新增数据
db.bakesales.insertMany( [
{ date: new ISODate("2019-01-28"), item: "Cake - Chocolate", quantity: 3, amount: new NumberDecimal("90") },
{ date: new ISODate("2019-01-28"), item: "Cake - Peanut Butter", quantity: 2, amount: new NumberDecimal("32") },
{ date: new ISODate("2019-01-30"), item: "Cake - Red Velvet", quantity: 1, amount: new NumberDecimal("20") },
{ date: new ISODate("2019-01-30"), item: "Cookies - Chocolate Chip", quantity: 6, amount: new NumberDecimal("24") },
{ date: new ISODate("2019-01-31"), item: "Pie - Key Lime", quantity: 2, amount: new NumberDecimal("40") },
{ date: new ISODate("2019-01-31"), item: "Pie - Banana Cream", quantity: 2, amount: new NumberDecimal("40") },
{ date: new ISODate("2019-02-01"), item: "Cake - Red Velvet", quantity: 5, amount: new NumberDecimal("100") },
{ date: new ISODate("2019-02-01"), item: "Tarts - Apple", quantity: 2, amount: new NumberDecimal("8") },
{ date: new ISODate("2019-02-02"), item: "Cake - Chocolate", quantity: 2, amount: new NumberDecimal("60") },
{ date: new ISODate("2019-02-02"), item: "Cake - Peanut Butter", quantity: 1, amount: new NumberDecimal("16") },
{ date: new ISODate("2019-02-03"), item: "Cake - Red Velvet", quantity: 5, amount: new NumberDecimal("100") }
] );
updateMonthlySales(new ISODate("2019-01-01"));
# 查询结果
db.monthlybakesales.find({}).sort({_id:1});
# 输出
{ "_id" : "2018-12", "sales_quantity" : 41, "sales_amount" : NumberDecimal("506") }
{ "_id" : "2019-01", "sales_quantity" : 102, "sales_amount" : NumberDecimal("1142") }
{ "_id" : "2019-02", "sales_quantity" : 15, "sales_amount" : NumberDecimal("284") }