MongoDB 聚合

MongoDB 中,聚合(Aggregation)是一种用于处理和分析数据的强大工具。聚合框架提供了一组操作符,可以对集合中的文档进行分组、筛选、排序、转换等操作,以生成新的结果集。聚合操作可以用于复杂的数据处理和分析任务,例如统计、分组计算、数据透视等。

聚合框架的核心是管道(Pipeline),它由一系列操作符组成,每个操作符都会对输入文档进行处理,并将结果传递给下一个操作符。聚合操作符可以按照顺序组合,以实现复杂的数据处理逻辑。

以下是一些常用的聚合操作符:

  • $match:用于筛选文档,类似于查询中的 find() 方法。

  • $group:用于分组文档,并对每个组进行聚合计算,如求和、平均值等。

  • $project:用于投影文档,即选择需要的字段,并可以进行计算和重命名等操作。

  • $sort:用于对文档进行排序。

  • $limit:用于限制输出文档的数量。

  • $skip:用于跳过指定数量的文档。

  • $unwind:用于展开数组字段,将数组中的每个元素作为独立的文档。

以下是一个使用聚合框架的示例,假设有一个名为 orders 的集合,包含了订单信息:

db.orders.aggregate([
 { $match: { status: "completed" } },  // 筛选状态为 "completed" 的订单
 { $group: { _id: "$customer", total: { $sum: "$amount" } } },  // 按客户 customer 分组,并计算订单总金额
 { $sort: { total: -1 } },  // 按总金额降序排序
 { $limit: 10 }  // 只返回前 10 个结果
]);

上面的聚合操作首先筛选出状态为 “completed” 的订单,然后按客户分组,并计算每个客户的订单总金额,然后按总金额降序排序,并只返回前 10 个结果。

注意:聚合操作是在数据库服务器上执行的,可以利用数据库的计算能力和索引来提高性能。聚合操作还可以与其他查询操作(如查询条件、索引等)组合使用,以实现更复杂的数据处理需求。

aggregate() 方法

MongoDB 中聚合的方法使用 aggregate()。aggregate() 方法的基本语法格式如下所示:

db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)

其中,COLLECTION_NAME 为集合名称,AGGREGATE_OPERATION 为聚合操作对。

aggregate() 示例

该示例将计算 col 集合中各种 sex 的 age 平均值。

(1)col 集合中的数据如下:

> db.col.find()
{ "_id" : ObjectId("64e71af810366fa87109a12f"), "name" : "张三", "age" : 18, "email" : "zhangsan@outlook.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a130"), "name" : "李四", "age" : 22, "email" : "lisi@qq.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a131"), "name" : "王五", "age" : 26, "email" : "wangwu@sina.com.cn", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a132"), "name" : "赵六", "age" : 27, "email" : "zhaoliu@gmail.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a133"), "name" : "顾七", "age" : 30, "email" : "guqi@qq.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a134"), "name" : "何八", "age" : 42, "email" : "heba@outlook.com", "sex" : "male" }

(2)计算各个 sex 下 age 的平均值:

> db.col.aggregate({ $group:{_id:"$sex", avg_age:{$avg:"$age"}} })
{ "_id" : "male", "avg_age" : 29 }
{ "_id" : "female", "avg_age" : 24.5 }

以上示例类似的 sql 语句:

select sex, avg(age) from col group by sex;

在上面的例子中,我们通过字段 sex 字段对数据进行分组,并计算每个分组中 age 字段的平均值。

管道(Pipeline)

管道在 Unix 和 Linux 中一般用于将当前命令的输出结果作为下一个命令的参数。例如:

# 在文件中找出重复的行
$ sort testfile1 | uniq -d
Hello 95  
Linux 85
test 30

上面示例中,符号 | 就是管道符号。

在 MongoDB 中,MongoDB 的聚合管道将 MongoDB 文档在一个管道处理完毕后将结果传递给下一个管道处理,管道操作是可以重复的。

注意:聚合表达式处理输入文档并输出。表达式是无状态的,只能用于计算当前聚合管道的文档,不能处理其它的文档。

管道操作符实例

$project

$project 操作符用于将聚合管道中的文档转换为指定的字段集合。它可以用于选择要返回的字段,计算新的字段值,重命名字段等操作。

$project 操作符接受一个包含字段映射的对象作为参数,其中键表示要包含或排除的字段,值表示是否包含或排除该字段。可以使用1表示包含该字段,0表示排除该字段。例如:

# col 集合所有数据
> db.col.find()
{ "_id" : ObjectId("64e71af810366fa87109a12f"), "name" : "张三", "age" : 18, "email" : "zhangsan@outlook.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a130"), "name" : "李四", "age" : 22, "email" : "lisi@qq.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a131"), "name" : "王五", "age" : 26, "email" : "wangwu@sina.com.cn", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a132"), "name" : "赵六", "age" : 27, "email" : "zhaoliu@gmail.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a133"), "name" : "顾七", "age" : 30, "email" : "guqi@qq.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a134"), "name" : "何八", "age" : 42, "email" : "heba@outlook.com", "sex" : "male" }

# 通过投影,仅输出 name 和 age 字段,默认情况下 _id 字段是被包含的
> db.col.aggregate({ $project:{ name:1, age:1 } })
{ "_id" : ObjectId("64e71af810366fa87109a12f"), "name" : "张三", "age" : 18 }
{ "_id" : ObjectId("64e71af810366fa87109a130"), "name" : "李四", "age" : 22 }
{ "_id" : ObjectId("64e71af810366fa87109a131"), "name" : "王五", "age" : 26 }
{ "_id" : ObjectId("64e71af810366fa87109a132"), "name" : "赵六", "age" : 27 }
{ "_id" : ObjectId("64e71af810366fa87109a133"), "name" : "顾七", "age" : 30 }
{ "_id" : ObjectId("64e71af810366fa87109a134"), "name" : "何八", "age" : 42 }

# 通过投影,禁止输出 _id 字段,允许输出 name 和 age 字段
> db.col.aggregate({ $project:{ _id:0, name:1, age:1 } })
{ "name" : "张三", "age" : 18 }
{ "name" : "李四", "age" : 22 }
{ "name" : "王五", "age" : 26 }
{ "name" : "赵六", "age" : 27 }
{ "name" : "顾七", "age" : 30 }
{ "name" : "何八", "age" : 42 }

$project 操作符还支持一些表达式和操作符,可以用于计算新的字段值。常用的表达式和操作符包括算术操作符(如 $add、$subtract、$multiply、$divide)、逻辑操作符(如 $and、$or、$not)、条件操作符(如 $ifNull、$cond)、字符串操作符(如 $concat、$substr)、日期操作符(如 $year、$month、$dayOfMonth)等。例如:

# col 集合所有数据
> db.col.find()
{ "_id" : ObjectId("64e71af810366fa87109a12f"), "name" : "张三", "age" : 27, "email" : "zhangsan@outlook.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a130"), "name" : "李四", "age" : 22, "email" : "lisi@qq.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a131"), "name" : "王五", "age" : 27, "email" : "wangwu@sina.com.cn", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a132"), "name" : "赵六", "age" : 22, "email" : "zhaoliu@gmail.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a133"), "name" : "顾七", "age" : 30, "email" : "guqi@qq.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a134"), "name" : "何八", "age" : 42, "email" : "heba@outlook.com", "sex" : "male" }

# 使用 $multiply 操作符对 age 字段的值乘以 10
> db.col.aggregate({ $project:{_id:0, name:1, age:{$multiply:["$age",10]}} })
{ "name" : "张三", "age" : 270 }
{ "name" : "李四", "age" : 220 }
{ "name" : "王五", "age" : 270 }
{ "name" : "赵六", "age" : 220 }
{ "name" : "顾七", "age" : 300 }
{ "name" : "何八", "age" : 420 }

$match

$match 操作符用于筛选文档,类似于查询中的find()方法。它可以根据指定的条件选择符合条件的文档,并将它们作为聚合管道的输入。

$match 操作符接受一个查询条件作为参数,可以使用各种查询运算符和表达式来构建条件。常用的查询运算符包括$eq(等于)、$ne(不等于)、$gt(大于)、$lt(小于)、$gte(大于等于)、$lte(小于等于)、$in(在给定数组中)、$nin(不在给定数组中)等。例如:

# col 集合所有数据
> db.col.find()
{ "_id" : ObjectId("64e71af810366fa87109a12f"), "name" : "张三", "age" : 18, "email" : "zhangsan@outlook.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a130"), "name" : "李四", "age" : 22, "email" : "lisi@qq.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a131"), "name" : "王五", "age" : 26, "email" : "wangwu@sina.com.cn", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a132"), "name" : "赵六", "age" : 27, "email" : "zhaoliu@gmail.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a133"), "name" : "顾七", "age" : 30, "email" : "guqi@qq.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a134"), "name" : "何八", "age" : 42, "email" : "heba@outlook.com", "sex" : "male" }

# 通过 $match 获取 age 大于 20 的文档,然后根据 sex 进行分组,计算每个分组 age 的平均值
> db.col.aggregate([ {$match:{age:{$gt:20}}}, {$group:{_id:"$sex", avg_age:{$avg:"$age"}}} ])
{ "_id" : "female", "avg_age" : 24.5 }
{ "_id" : "male", "avg_age" : 32.666666666666664 }

注意:$match 操作符可以利用集合上的索引来提高查询性能。因此,在使用 $match 操作符时,应该根据查询条件创建适当的索引,以获得更好的性能。

$skip

$skip 操作符用于在聚合管道中跳过指定数量的文档,并返回剩余的文档。它可以用于实现分页功能,或者在聚合操作中跳过不需要的文档。

$skip 操作符接受一个整数作为参数,表示要跳过的文档数量。该参数必须是一个非负整数。例如:

# col 集合所有数据
> db.col.find()
{ "_id" : ObjectId("64e71af810366fa87109a12f"), "name" : "张三", "age" : 18, "email" : "zhangsan@outlook.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a130"), "name" : "李四", "age" : 22, "email" : "lisi@qq.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a131"), "name" : "王五", "age" : 26, "email" : "wangwu@sina.com.cn", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a132"), "name" : "赵六", "age" : 27, "email" : "zhaoliu@gmail.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a133"), "name" : "顾七", "age" : 30, "email" : "guqi@qq.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a134"), "name" : "何八", "age" : 42, "email" : "heba@outlook.com", "sex" : "male" }

# 使用 $skip 操作符跳过前 4 个文档
> db.col.aggregate({ $skip:4 })
{ "_id" : ObjectId("64e71af810366fa87109a133"), "name" : "顾七", "age" : 30, "email" : "guqi@qq.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a134"), "name" : "何八", "age" : 42, "email" : "heba@outlook.com", "sex" : "male" }

注意:$skip 操作符应该尽量在聚合管道的早期使用,以避免在后续的操作中处理不必要的文档。如果在聚合管道的后期使用 $skip 操作符,将会对性能产生负面影响,因为在跳过文档之前,MongoDB 仍然需要执行前面的聚合操作。

另外,如果要实现分页功能,可以将 $skip 操作符与 $limit 操作符结合使用。$limit 操作符用于限制返回的文档数量,可以用于分页查询。例如:

# col 集合所有数据
> db.col.find()
{ "_id" : ObjectId("64e71af810366fa87109a12f"), "name" : "张三", "age" : 27, "email" : "zhangsan@outlook.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a130"), "name" : "李四", "age" : 22, "email" : "lisi@qq.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a131"), "name" : "王五", "age" : 27, "email" : "wangwu@sina.com.cn", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a132"), "name" : "赵六", "age" : 22, "email" : "zhaoliu@gmail.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a133"), "name" : "顾七", "age" : 30, "email" : "guqi@qq.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a134"), "name" : "何八", "age" : 42, "email" : "heba@outlook.com", "sex" : "male" }

# 跳过 col 集合前 3 个文档,然后仅仅获取 2 个文档
> db.col.aggregate([{ $skip:3 }, { $limit:2 }])
{ "_id" : ObjectId("64e71af810366fa87109a132"), "name" : "赵六", "age" : 22, "email" : "zhaoliu@gmail.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a133"), "name" : "顾七", "age" : 30, "email" : "guqi@qq.com", "sex" : "male" }

$sum

计算总和。例如:

# col 集合所有数据
> db.col.find()
{ "_id" : ObjectId("64e71af810366fa87109a12f"), "name" : "张三", "age" : 18, "email" : "zhangsan@outlook.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a130"), "name" : "李四", "age" : 22, "email" : "lisi@qq.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a131"), "name" : "王五", "age" : 26, "email" : "wangwu@sina.com.cn", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a132"), "name" : "赵六", "age" : 27, "email" : "zhaoliu@gmail.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a133"), "name" : "顾七", "age" : 30, "email" : "guqi@qq.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a134"), "name" : "何八", "age" : 42, "email" : "heba@outlook.com", "sex" : "male" }

# 使用 sex 进行分组,计算每个分组 age 的总和
> db.col.aggregate({ $group:{_id:"$sex", age_sum:{$sum:"$age"}} })
{ "_id" : "male", "age_sum" : 116 }
{ "_id" : "female", "age_sum" : 49 }

$avg

计算平均值。例如:

# col 集合所有数据
> db.col.find()
{ "_id" : ObjectId("64e71af810366fa87109a12f"), "name" : "张三", "age" : 18, "email" : "zhangsan@outlook.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a130"), "name" : "李四", "age" : 22, "email" : "lisi@qq.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a131"), "name" : "王五", "age" : 26, "email" : "wangwu@sina.com.cn", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a132"), "name" : "赵六", "age" : 27, "email" : "zhaoliu@gmail.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a133"), "name" : "顾七", "age" : 30, "email" : "guqi@qq.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a134"), "name" : "何八", "age" : 42, "email" : "heba@outlook.com", "sex" : "male" }

# 使用 sex 进行分组,计算每个分组 age 的平均值
> db.col.aggregate({ $group:{_id:"$sex", age_avg:{$avg:"$age"}} })
{ "_id" : "female", "age_avg" : 24.5 }
{ "_id" : "male", "age_avg" : 29 }

$min

获取集合中所有文档对应值得最小值。例如:

# col 集合所有数据
> db.col.find()
{ "_id" : ObjectId("64e71af810366fa87109a12f"), "name" : "张三", "age" : 18, "email" : "zhangsan@outlook.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a130"), "name" : "李四", "age" : 22, "email" : "lisi@qq.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a131"), "name" : "王五", "age" : 26, "email" : "wangwu@sina.com.cn", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a132"), "name" : "赵六", "age" : 27, "email" : "zhaoliu@gmail.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a133"), "name" : "顾七", "age" : 30, "email" : "guqi@qq.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a134"), "name" : "何八", "age" : 42, "email" : "heba@outlook.com", "sex" : "male" }

# 使用 sex 进行分组,获取每个分组最小的 age 值
> db.col.aggregate({ $group:{_id:"$sex", age_min:{$min:"$age"}} })
{ "_id" : "male", "age_min" : 18 }
{ "_id" : "female", "age_min" : 22 }

$max

获取集合中所有文档对应值得最大值。例如:

# col 集合所有数据
> db.col.find()
{ "_id" : ObjectId("64e71af810366fa87109a12f"), "name" : "张三", "age" : 18, "email" : "zhangsan@outlook.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a130"), "name" : "李四", "age" : 22, "email" : "lisi@qq.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a131"), "name" : "王五", "age" : 26, "email" : "wangwu@sina.com.cn", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a132"), "name" : "赵六", "age" : 27, "email" : "zhaoliu@gmail.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a133"), "name" : "顾七", "age" : 30, "email" : "guqi@qq.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a134"), "name" : "何八", "age" : 42, "email" : "heba@outlook.com", "sex" : "male" }

# 使用 sex 进行分组,获取每个分组最大的 age 值
> db.col.aggregate({ $group:{_id:"$sex", age_max:{$max:"$age"}} })
{ "_id" : "female", "age_max" : 27 }
{ "_id" : "male", "age_max" : 42 }

$push

将值加入一个数组中,不会判断是否有重复的值。例如:

# col 集合所有数据
> db.col.find()
{ "_id" : ObjectId("64e71af810366fa87109a12f"), "name" : "张三", "age" : 18, "email" : "zhangsan@outlook.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a130"), "name" : "李四", "age" : 22, "email" : "lisi@qq.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a131"), "name" : "王五", "age" : 26, "email" : "wangwu@sina.com.cn", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a132"), "name" : "赵六", "age" : 27, "email" : "zhaoliu@gmail.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a133"), "name" : "顾七", "age" : 30, "email" : "guqi@qq.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a134"), "name" : "何八", "age" : 42, "email" : "heba@outlook.com", "sex" : "male" }

# 使用 sex 进行分组,将每个分组的 age 组成一个数组
> db.col.aggregate({ $group:{_id:"$sex", ages:{$push:"$age"}} })
{ "_id" : "female", "ages" : [ 22, 22 ] }
{ "_id" : "male", "ages" : [ 27, 27, 30, 42 ] }

$addToSet

将值加入一个数组中,会判断是否有重复的值,若相同的值在数组中已经存在了,则不加入。例如:

# col 集合所有数据
> db.col.find()
{ "_id" : ObjectId("64e71af810366fa87109a12f"), "name" : "张三", "age" : 27, "email" : "zhangsan@outlook.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a130"), "name" : "李四", "age" : 22, "email" : "lisi@qq.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a131"), "name" : "王五", "age" : 27, "email" : "wangwu@sina.com.cn", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a132"), "name" : "赵六", "age" : 22, "email" : "zhaoliu@gmail.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a133"), "name" : "顾七", "age" : 30, "email" : "guqi@qq.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a134"), "name" : "何八", "age" : 42, "email" : "heba@outlook.com", "sex" : "male" }

# 使用 sex 进行分组,将每个分组的 age 组成一个数组
> db.col.aggregate({ $group:{_id:"$sex", ages:{$addToSet:"$age"}} })
{ "_id" : "male", "ages" : [ 27, 42, 30 ] }
{ "_id" : "female", "ages" : [ 22 ] }

$first

根据资源文档的排序获取第一个文档数据。例如:

# col 集合所有数据
> db.col.find()
{ "_id" : ObjectId("64e71af810366fa87109a12f"), "name" : "张三", "age" : 18, "email" : "zhangsan@outlook.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a130"), "name" : "李四", "age" : 22, "email" : "lisi@qq.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a131"), "name" : "王五", "age" : 26, "email" : "wangwu@sina.com.cn", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a132"), "name" : "赵六", "age" : 27, "email" : "zhaoliu@gmail.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a133"), "name" : "顾七", "age" : 30, "email" : "guqi@qq.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a134"), "name" : "何八", "age" : 42, "email" : "heba@outlook.com", "sex" : "male" }

# 使用 sex 进行分组,获取每个分组文档中第一个文档的 age 值
> db.col.aggregate({ $group:{_id:"$sex", age:{$first:"$age"}} })
{ "_id" : "female", "age" : 22 }
{ "_id" : "male", "age" : 18 }

$last

根据资源文档的排序获取最后一个文档数据。例如:

# col 集合所有数据
> db.col.find()
{ "_id" : ObjectId("64e71af810366fa87109a12f"), "name" : "张三", "age" : 18, "email" : "zhangsan@outlook.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a130"), "name" : "李四", "age" : 22, "email" : "lisi@qq.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a131"), "name" : "王五", "age" : 26, "email" : "wangwu@sina.com.cn", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a132"), "name" : "赵六", "age" : 27, "email" : "zhaoliu@gmail.com", "sex" : "female" }
{ "_id" : ObjectId("64e71af810366fa87109a133"), "name" : "顾七", "age" : 30, "email" : "guqi@qq.com", "sex" : "male" }
{ "_id" : ObjectId("64e71af810366fa87109a134"), "name" : "何八", "age" : 42, "email" : "heba@outlook.com", "sex" : "male" }

# 使用 sex 进行分组,获取每个分组文档中最后一个文档的 age 值
> db.col.aggregate({ $group:{_id:"$sex", age:{$last:"$age"}} })
{ "_id" : "female", "age" : 27 }
{ "_id" : "male", "age" : 42 }
说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号