抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

摘要:本文学习了如何使用聚合查询,包括管道操作符和聚合操作符的使用。

环境

Windows 10 企业版 LTSC 21H2
MongoDB 6.0.21

1 介绍

聚合是将复杂的查询分解为多个阶段,每个阶段使用操作符定义操作方式,最后将所有的阶段聚合形成结果并返回。

操作符分为管道操作符和聚合操作符,管道操作符定义阶段,聚合操作符需要在特定的管道操作符中使用,得到相应的聚合结果。

2 规范

语法:

sql
1
db.集合名.aggregate(pipeline)

含义:

名称 类型 说明
pipeline 文档或数组 由操作符组成的多个阶段

3 使用

3.1 管道操作符

3.1.1 match

用于过滤文档,只允许匹配条件的文档通过。

根据查询条件过滤文档:

sql
1
{$match: <query>}

含义:

名称 类型 说明
query 文档 要查询的文档,支持通过查询操作符匹配,不支持聚合操作符匹配,如果需要支持聚合操作符匹配,应该在$expr中使用

查询age属性等于25的文档:

sql
1
db.student.aggregate({$match: {age: {$eq: 25}}});

等价于:

sql
1
db.student.find({age: {$eq: 25}});

3.1.2 project

用于定制返回结果,指定返回的属性,支持别名。

根据规则定制返回结果:

sql
1
{$project: <projections>}

含义:

名称 类型 说明
projections 文档 返回属性的规则,支持包含和排除,以及重命名

查询name属性,并排除_id属性:

sql
1
db.student.aggregate({$project: {_id: 0, name: 1}});

查询name属性和addr属性,并将addr属性重命名为address属性:

sql
1
2
db.student.aggregate({$project: {_id: 0, name: 1, address: "$addr"}}
);

3.1.3 sort

用于对文档进行排序。

根据规则对文档进行排序:

sql
1
{$sort: <rules>}

含义:

名称 类型 说明
rules 文档 排序规则,使用键值对形式

查询文档,按age属性和sex属性排序并返回:

sql
1
db.student.aggregate({$sort: {age: 1, sex: 1}});

等价于:

sql
1
2
db.student.find()
.sort({age: 1, sex: 1});

3.1.4 skip

用于跳过指定数量的文档。

跳过指定数量的文档:

sql
1
{$skip: <skipNum>}

含义:

名称 类型 说明
skipNum 整型 跳过的文档数量

跳过前2条文档:

sql
1
db.student.aggregate({$skip: 2});

等价于:

sql
1
2
db.student.find()
.skip(2);

3.1.5 limit

用于查询指定数量的文档。

查询指定数量的文档:

sql
1
{$limit: <limitNum>}

含义:

名称 类型 说明
limitNum 整型 查询的文档数量

查询前2条文档:

sql
1
db.student.aggregate({$limit: 2});

等价于:

sql
1
2
db.student.find()
.limit(2);

3.1.6 count

用于统计查询的文档数量。

统计查询的文档数量:

sql
1
{$count: <countName>}

含义:

名称 类型 说明
countName 字符串 输出的统计名称

统计查询的文档数量,并将count作为名称返回:

sql
1
db.student.aggregate({$count: "count"});

3.1.7 group

用于对文档分组,并执行聚合操作。

统计查询的文档数量:

sql
1
2
3
4
5
6
{
$group: {
_id: <expression>,
<field>: {<operator>: <expression>}
}
}

含义:

名称 类型 说明
field 属性 返回的属性,可选,可以有多个
operator 操作符 通过操作符处理返回的属性
expression 字符串或文档 用于操作符处理的表达式,可以使用$属性的方式指定属性

对文档分组,统计数量:

sql
1
2
3
4
5
6
db.student.aggregate({
$group: {
_id: null,
count: {$count: {}}
}
});

对文档按sex属性分组,统计文档数量:

sql
1
2
3
4
5
6
db.student.aggregate({
$group: {
_id: "$sex",
sexCount: {$count: {}}
}
});

$group中使用的$count是聚合操作符,并不是管道操作符。

3.1.8 lookup

用于将多个集合中的文档关联查询。

3.1.8.1 单个条件

单个条件的关联查询:

sql
1
2
3
4
5
6
7
8
{
$lookup: {
from: <collectionName>,
localField: <localFieldName>,
foreignField: <foreignFieldName>,
as: <asName>
}
}

含义:

名称 类型 说明
collectionName 字符串 同一个数据库中的关联集合
localFieldName 字符串 本地集合中的属性,用于同关联集合中的属性关联
foreignFieldName 字符串 关联集合中的属性,用于同本地集合中的属性关联
asName 字符串 返回的属性名

单个条件的关联查询,将学校信息关联到学生信息表:

sql
1
2
3
4
5
6
7
8
db.student.aggregate({
$lookup: {
from: "school",
localField: "school",
foreignField: "_id",
as: "schoolInfo"
}
});

将学校信息关联到学生信息表:

sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"_id": 1,
"name": "张三",
"sex": "男",
"addr": "北京市 东城区",
"age": 25,
"expenditure": 80,
"income": 100,
"school": 2,
"total": 720,
"schoolInfo": [
{"_id": 2, "name": "北京大学", "score": 700}
]
}
3.1.8.2 多个条件

多个条件的关联查询:

sql
1
2
3
4
5
6
7
8
{
$lookup: {
from: <collectionName>,
let: {<localName>: <localFieldName>},
pipeline: [<operator>: <expression>],
as: <asName>
}
}

含义:

名称 类型 说明
collectionName 字符串 同一个数据库中的关联集合
let 文档 本地集合中的属性,可以有多个
localName 字符串 本地集合中的属性别名
localFieldName 字符串 本地集合中的属性别名对应的本地属性,使用$属性的方式指定本地集合属性
pipeline 数组 关联集合中的属性,使用管道操作符关联本地集合和关联集合,可以有多个
operator 操作符 通过操作符处理返回的属性
expression 字符串或文档 用于操作符处理的表达式,使用$属性的方式指定关联集合属性,使用$$属性的方式指定本地集合属性别名
asName 字符串 返回的属性名

多个条件的关联查询,将学校信息关联到学生信息表,并查询学生总分超过学校分数的文档:

sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
db.student.aggregate({
$lookup: {
from: "school",
let: {stuSchool: "$school", stuTotal: "$total"},
pipeline: [
{$match:
{$expr:
{$and: [
{$eq: ["$_id", "$$stuSchool"]},
{$lte: ["$score", "$$stuTotal"]}
]}
}
}
],
as: "schoolInfo"
}
});

将学校信息关联到学生信息表,并查询学生总分超过学校分数的文档:

sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"_id": 1,
"name": "张三",
"sex": "男",
"addr": "北京市 东城区",
"age": 25,
"expenditure": 80,
"income": 100,
"school": 2,
"total": 720,
"schoolInfo": [
{"_id": 2, "name": "北京大学", "score": 700}
]
}

3.2 聚合操作符

3.2.1 count

统计文档的数量。

统计数量不需要使用参数:

sql
1
{$count: {}}

对文档按sex属性分组,统计文档数量:

sql
1
2
3
4
5
6
db.student.aggregate({
$group: {
_id: "$sex",
sexCount: {$count: {}}
}
});

3.2.2 sum

计算并返回数字的总和。

$project中对数组属性求和,或者在$group中对数字属性求和:

sql
1
{$sum: <expression>}

$project中对数组属性求和:

sql
1
{$sum: [<expression>, <expression>]}

含义:

名称 类型 说明
expression 数字或属性 使用$属性的方式指定属性,忽略非数字的属性值

对文档按sex属性分组,统计文档数量并计算age属性的总和:

sql
1
2
3
4
5
6
7
db.student.aggregate({
$group: {
_id: "$sex",
sexCount: {$count: {}},
sexSumAge: {$sum: "$age"}
}
});

统计文档scores数组的总和作为totalScore属性返回,只显示name属性和totalScore属性:

sql
1
2
3
4
5
6
7
db.student.aggregate({
$project: {
_id: 0,
name: 1,
totalScore: {$sum: "$scores"}
}
});

3.2.3 avg

计算并返回数字的平均值。

$project中对数组属性求平均值,或者在$group中对数字属性求平均值:

sql
1
{$avg: <expression>}

$project中对数组属性求平均值:

sql
1
{$avg: [<expression>, <expression>]}

含义:

名称 类型 说明
expression 数字或属性 使用$属性的方式指定属性,忽略非数字的属性值

对文档按sex属性分组,统计文档数量并计算age属性的平均值:

sql
1
2
3
4
5
6
7
db.student.aggregate({
$group: {
_id: "$sex",
sexCount: {$count: {}},
sexAvgAge: {$avg: "$age"}
}
});

统计文档scores数组的平均值作为meanScore属性返回,只显示name属性和meanScore属性:

sql
1
2
3
4
5
6
7
db.student.aggregate({
$project: {
_id: 0,
name: 1,
meanScore: {$avg: "$scores"}
}
});

3.2.4 cond

条件表达式,根据条件执行表达式。

根据条件执行表达式:

sql
1
2
3
4
5
6
7
{
$cond: {
if: <expression>,
then: <trueCase>,
else: <falseCase>
}
}

含义:

名称 类型 说明
expression 文档 计算结果为布尔类型的表达式
trueCase 文档 计算结果为true时返回此表达式的结果
falseCase 文档 计算结果为false时返回此表达式的结果

统计文档scores数组的总和,根据是否超过250作为level属性,返回name属性和level属性:

sql
1
2
3
4
5
6
7
8
9
10
11
12
13
db.student.aggregate({
$project: {
_id: 0,
name: 1,
level: {
$cond: {
if: {$gt: [{$sum: "$scores"}, 250]},
then: "尖子生",
else: "普通生"
}
}
}
});

评论