在数据库领域,无论是SQL还是NoSQL数据库,聚合操作都是非常重要的一环。MongoDB提供了多种方式来执行聚合操作,包括聚合管道、map-reduce函数和特定聚合方法。本文将重点介绍聚合管道,并使用简单的示例来展示其主要部分。将通过MongoDB shell命令来执行聚合操作。
MongoDB的聚合框架基于数据处理管道的概念。聚合管道类似于UNIX世界中的管道。首先,集合中的文档逐个通过管道,然后经过一系列的处理阶段,最终得到结果集。
在聚合管道中,可以出现多个阶段,例如$project、$match、$group、$sort等。这些阶段可以多次出现。
以下是一个使用聚合管道的示例,将使用MongoDB shell命令来执行这个操作。
db.mycollection.aggregate([
{$match: { 'phone_type': 'smart' }},
{$group: { '_id': '$brand_name', total: {$sum: '$price' }}}
])
在这个示例中,首先通过$match阶段过滤文档,然后在下一个阶段对文档进行分组,最终得到结果集。
为了运行MongoDB shell命令,需要一个数据库和一些测试记录。让创建一个数据库和一个集合。
dept = ['IT', 'Sales', 'HR', 'Admin'];
for (i = 0; i < 10; i++) {
db.mycollection.insert({
_id: i,
emp_code: 'emp_' + i,
dept_name: dept[Math.round(Math.random() * 3)],
experience: Math.round(Math.random() * 10)
});
}
上面的命令将在名为mycollection的集合中插入一些测试文档。
聚合函数接受一个数组作为参数,在数组中可以传递管道的不同阶段。
db.mycollection.aggregate([
{$match: { 'phone_type': 'smart' }},
{$group: { '_id': '$brand_name', total: {$sum: '$price' }}}
])
在这个示例中,传递了两个管道阶段:$match用于过滤记录,$group用于对记录进行分组并生成最终的记录集。
在$project阶段,可以添加键、删除键、重塑键。还可以使用一些简单的函数,如$toUpper、$toLower、$add、$multiply等。
db.mycollection.aggregate([
{
$project: {
_id: 0,
department: {$toUpper: '$dept_name'},
new_experience: {$add: ['$experience', 1]}
}
}
])
在这个聚合查询中,正在投影文档。_id:0意味着隐藏了这个字段,创建了一个新的键名为department,使用之前的dept_name字段的大写形式。需要注意的是,字段‘dept_name’前缀为‘$’符号,以告诉MongoDB shell这个字段是文档的原始字段名。另一个新字段new_experience是通过使用$add函数将1添加到之前的experience字段来创建的。
$match的工作方式与SQL中的‘where子句’类似,用于过滤记录。可能想要匹配的原因是因为想要过滤结果,并且只聚合部分文档或在进行分组后搜索结果集的特定部分。
db.mycollection.aggregate([
{
$match: {
dept_name: 'Sales'
}
}
])
顾名思义,$group根据某个键对文档进行分组。假设想要根据部门名称对员工进行分组,并找出每个部门的员工数量。
db.mycollection.aggregate([
{
$group: {
_id: '$dept_name',
no_of_employees: {$sum: 1}
}
}
])
在这里,_id是分组的键,创建了一个新的键名为no_of_employees,并使用$sum来找出每个组的总记录数。
$sort帮助在聚合后按升序或降序排序数据。假设想要按部门名称的升序排列,并找出员工数量。
db.mycollection.aggregate([
{
$group: {
_id: '$dept_name',
no_of_employees: {$sum: 1}
}
},
{
$sort: {
_id: 1
}
}
])
对于降序,使用-1。在这里的$sort中,使用了_id字段,因为在聚合的第一个阶段,使用了$dept_name作为_id进行聚合。
$skip和$limit的工作方式与在简单查找时跳过和限制的方式相同。除非首先排序,否则跳过和限制没有意义,否则结果就是未定义的。
db.mycollection.aggregate([
{
$group: {
_id: '$dept_name',
no_of_employees: {$sum: 1}
}
},
{
$sort: {
_id: 1
}
},
{
$skip: 2
},
{
$limit: 1
}
])
文档被分组,然后排序,之后跳过两个文档,并将文档限制为一个。
正如知道排序在聚合管道中的工作方式,可以学习$first和$last。它们允许在聚合管道处理文档时,获取每个组的第一个和最后一个值。
db.mycollection.aggregate([
{
$group: {
_id: '$dept_name',
no_of_employees: {$sum: 1},
first_record: { $first: '$emp_code' }
}
}
])
正如所知,在MongoDB中,文档可以包含数组。在数组中进行分组并不容易。$unwind首先解组数组数据,然后基本上重新组合它,让可以在它上面进行分组计算。
{
a: somedata,
b: someotherdata,
c: [arr1, arr2, arr3]
}
在对‘c’进行$unwind之后,将得到三个文档:
{
a: somedata,
b: someotherdata,
c: arr1
}
{
a: somedata,
b: someotherdata,
c: arr2
}
{
a: somedata,
b: someotherdata,
c: arr3
}
让看看一些在SQL和MongoDB中都非常常见的表达式。有它们的替代品。