黑白客 发表于 2023-2-7 10:00

MongoDB按需实例化视图配置

# 前言
视图是MongoDB中重要的部分,使用中经常需要根据需要定制视图,本文将通过基础命令和实例介绍视图的使用。


---




# 1 $Merge
4.2版本开始添加了 $merge聚合管道阶段。 此阶段可以将管道结果合并到现有集合中,而不是完全替换该集合。此功能允许用户创建按需实例化视图,在该视图中,每次运行管道时都可以更新输出集合的内容。


# 2 定义按需实例化视图
以下updateMonthlySales功能定义了 monthlybakesales包含累积每月销售信息的实例化视图。在示例中,该函数采用日期参数以仅从特定日期开始更新每月销售信息

```java
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字段(默认为unsharded输出集合),阶段检查中聚集结果文档相匹配的集合中的现有文档:
>         如果存在匹配项(即,集合中已经存在具有相同年份月份的文档),则阶段将使用汇总结果中的文档替换现有文档。
如果没有匹配项,那么阶段会将聚合结果中的文档插入到集合中(不匹配时的默认行为)。

## 执行初始运行

```java
updateMonthlySales(new ISODate("1970-01-01"));

```
初次运行后, 查看
> db.monthlybakesales.find().sort( { _id: 1 } )

## 刷新物化视图
刷新数据,再次运行函数以重新运行聚合管道

>updateMonthlySales(new ISODate("2019-01-01"));

## 其它
$merge 阶段:
- 可以输出到相同,不同数据库中的集合
- 如果输出集合尚不存在,则创建一个新集合
- 可以将结果合并到现有集合中 (插入新文档,合并文档,替换文档,保留现有文档,使操作失败,使用自定义更新管道处理文档)
- 可以输出到分片集合,输入集合也可以分片


# 3 上限集合
上限集合是有固定大小的集合,提供高吞吐量操作,这些操作根据插入顺序和检索文档。封顶集合的工作方式类似于循环缓冲区。一旦集合填充了其分配的空间,它就会通过覆盖集合中最久的文档为新文档提供空间。

> 作为上限集合的替代方法,请考虑MongoDB的TTL索引。如通过设置TTL从集合中使数据过期。这些索引可以基于日期类型字段的值和索引的TTL值使得正常的集合中的数据过期删除

## 潜在使用场景
- 存储大容量系统的日志信息,在没有索引的情况下,将数据插入到上限集合中和效率接近于将日志信息直接插入到文件系统中的速度。因此内置的先进先出属性可以在管理数据的同时,保证数据的顺序。
- 在一个上限集合中缓存少量数据,由于读取的是高速缓存而不是大量的高速缓存,因此需要确保此集合始终保留在工作集中,那么需要对所需的一个或多个索引进行写操作。

## _id索引
上限集合 默认具有一个_id字段和该字段的索引_id

## 建议
> 更新: 如果您打算更新上限集合中的文档,请创建索引,以便这些更新操作不需要集合扫描

> 文档删除: 无法从上限集合中删除文档,要从集合中删除所有文档请使用drop() 方法删除集合并重新创建有上限的集合

> 分片:无法将有上限的集合分片

> 查询效率:使用自然顺序可以有效地从集合中检索最近插入的元素。这类似于日志文件上的tail

> 聚合 $out :聚合管道阶段 无法将结果写入上限集合

## 创建上限集合
使用 db.createCollection()方法显式创建带上限的集合,该方法是命令mongo外壳程序中的帮助器create。创建有上限的集合时,您必须指定集合最大大小,MongoDB将为上限集合预先分配最大大小。
```java
db.createCollection( "log", { capped: true, size: 100000 } )
```

如果size字段小于等于4096字节,MongoDB将提供4096字节。否者,MongoDB将提高提供的大小使其成为4096字节的整数倍。

还可以通过max字段指定集合中最多的文档数
> db.createCollection("log", { capped : true, size : 5242880, max : 5000 } )

`即使使用了max,也同样需要有size参数。如果在程序中达到了最大size数,但是没有达到max,MongoDB也会删除旧的文档`

## 查询上限集合
使用find() 查询上限集合,在没有任何排序的情况下,MongoDB将保证结果和插入的顺序一致。
要以相反的顺序检索文档,使用.sort()加$natural发送-1。
> db.cappedCollection.find().sort( { $natural: -1 } )

## 检查一个集合是否有上限
> db.collection.isCapped()

## 将集合转化为有上限的集合
> db.runCommand( { "convertoCapped": "mycoll" , size : 100000});

该size以字节为单位指定集合上限大小。
执行此操作期间,线程将持有数据库的排它锁,同一数据库的其它操作将被阻止。

seawaycao 发表于 2023-2-7 12:19

谢谢分享。很实用的教程!
页: [1]
查看完整版本: MongoDB按需实例化视图配置