## MongoDB的聚合操作

### MongoDB的聚合是什么

聚合(aggregate)是基于数据处理的聚合管道，每个文档通过一个由多个阶段（stage）组成的管道，可以对每个阶段的管道进行分组、过滤等功能，然后经过一系列的处理，输出相应的结果。

语法：`db.集合名称.aggregate({管道:{表达式}})`

### 常用管道命令

在mongodb中，⽂档处理完毕后， 通过管道进⾏下⼀次处理 常用管道命令如下：

- `$group`： 将集合中的⽂档分组， 可⽤于统计结果
- `$match`： 过滤数据， 只输出符合条件的⽂档
- `$project`： 修改输⼊⽂档的结构， 如重命名、 增加、 删除字段、 创建计算结果
- `$sort`： 将输⼊⽂档排序后输出
- `$limit`： 限制聚合管道返回的⽂档数
- `$skip`： 跳过指定数量的⽂档， 并返回余下的⽂档

### 常用表达式

表达式：处理输⼊⽂档并输出 语法：`表达式:'$列名'` 常⽤表达式:

- `$sum`： 计算总和， $sum:1 表示以⼀倍计数
- `$avg`： 计算平均值
- `$min`： 获取最⼩值
- `$max`： 获取最⼤值
- `$push`： 在结果⽂档中插⼊值到⼀个数组中

### 管道命令之`$group`

#### 按照某个字段进行分组

`$group`是所有聚合命令中用的最多的一个命令，用来将集合中的文档分组，可用于统计结果

其中注意点：

- `db.db_name.aggregate`是语法，所有的管道命令都需要写在其中
- `_id` 表示分组的依据，按照哪个字段进行分组，需要使用`$gender`表示选择这个字段进行分组
- `$sum:1` 表示把每条数据作为1进行统计，统计的是该分组下面数据的条数

#### group by null

当我们需要统计整个文档的时候，`$group` 的另一种用途就是把整个文档分为一组进行统计

其中注意点：`_id:null` 表示不指定分组的字段，即统计整个文档，此时获取的`counter`表示整个文档的个数

#### 数据透视

正常情况在统计的不同性别的数据的时候，需要知道所有的name，需要逐条观察，如果通过某种方式把所有的name放到一起，那么此时就可以理解为数据透视

### 管道命令之`$match`

`$match`用于进行数据的过滤，是在能够在聚合操作中使用的命令，和`find`区别在于`$match` 操作可以把结果交给下一个管道处理，而`find`不行

### 管道命令之`$project`

`$project`用于修改文档的输入输出结构，例如重命名，增加，删除字段

### 管道命令之`$sort`

`$sort`用于将输入的文档排序后输出

### 管道命令之`$skip` 和 `$limit`

- `$limit`限制返回数据的条数
- `$skip` 跳过指定的文档数，并返回剩下的文档数
- 同时使用时先使用skip在使用limit

## Mongdb的索引

### 为什么mongdb需要创建索引

- 加快查询速度
- 进行数据的去重

### mongodb创建简单的索引方法

- 语法：
  - `db.集合.ensureIndex({属性:1})`，1表示升序， -1表示降序
  - `db.集合.createIndex({属性:1})`
  - 上面两个命令效果等价
- 具体操作：db.db_name.ensureIndex({name:1})

### 创建索引前后查询速度对比

测试：插入10万条数据到数据库中 插入数据：

```js
for(i=0;i<100000;i++){db.t255.insert({name:'test'+i,age:i})}
```

创建索引前：

```
db.t1.find({name:'test10000'})
db.t1.find({name:'test10000'}).explain('executionStats')
```

创建索引后：

```js
db.t255.ensureIndex({name:1})
db.t1.find({name:'test10000'}).explain('executionStats')
```

### 索引的查看

默认情况下_id是集合的索引

查看方式：`db.collection_name.getIndexes()`

### mongodb创建唯一索引

在默认情况下mongdb的索引字段的值是可以相同的,仅仅能够提高查询速度

添加唯一索引的语法：

```js
db.collection_name.ensureIndex({"name":1},{"unique":true})
```

### 删除索引

语法：`db.t1.dropIndex({'索引名称':1})`

### 建立复合索引

在进行数据去重的时候，可能用一个字段来保证数据的唯一性，这个时候可以考虑建立复合索引来实现。

建立复合索引的语法：`db.collection_name.ensureIndex({字段1:1,字段2:1})`

### 建立索引注意点

- 根据需要选择是否需要建立唯一索引
- 索引字段是升序还是降序在单个索引的情况下不影响查询效率，但是带复合索引的条件下会有影响

## mongodb的备份和恢复

### 备份

备份的语法：

```
mongodump -h dbhost -d dbname -o dbdirectory
```

- `-h`： 服务器地址， 也可以指定端⼝号
- `-d`： 需要备份的数据库名称
- `-o`： 备份的数据存放位置， 此⽬录中存放着备份出来的数据

### 恢复

恢复语法：`mongorestore -h dbhost -d dbname --dir dbdirectory`

- `-h`： 服务器地址
- `-d`： 需要恢复的数据库实例
- `--dir`： 备份数据所在位置