MongoDB使用详解_4_常用聚合操作详解

1.测试数据

emp集合

db.emp.insert(
    [
        {
            _id: 1,
            name: "tom",
            age: 13,
            likes: ["basketball", "football"],
            sex: "F",
            dept_id: 1
        },
        {
            _id: 2,
            name: "jack",
            age: 14,
            likes: ["games", "douyin"],
            sex: "M",
            dept_id: 2
        },
        {
            _id: 3,
            name: "amy",
            age: 23,
            likes: ["code", "basketball"],
            sex: "F",
            dept_id: 1
        },
        {
            _id: 4,
            name: "musk",
            age: 42,
            likes: ["car", "space"],
            sex: "F",
            dept_id: 2
        },
        {
            _id: 5,
            name: "paul",
            age: 34,
            likes: [],
            sex: "F",
            dept_id: 2
        }
    ]
)

dept集合

db.dept.insert(
    [
        {
            _id: 1,
            d_name: "研发部"
        },
        {
            _id: 2,
            d_name: "运维部"
        }
    ]
)

2.简单演示

一个简单的聚合操作如下,这个聚合操作会经过两个阶段的数据处理:

  • 第一个管道阶段为 $match:会筛选出所有sex值为F 并且 dept_id 为2 的文档,然后输出到下一个管道操作中;
  • 第二个管道阶段为 $project:用于定义返回的字段内容,这里返回 _id name sex dept_id 以及自定义的字段名emp_name取值为name的值
db.emp.aggregate([
    {
        $match: {
            sex: "F", //匹配 sex = F的
            dept_id: 2 //匹配 dept_id = 2的
        }
    },
    {
        $project: {
            //映射,1显示,0不显示
            _id: 1,
            name: 1,
            sex: 1,
            dept_id: 1,
        }
    }
])

运行结果

在这里插入图片描述

Java代码

    @Test
    void agg() {
        Aggregation aggregation = Aggregation.newAggregation(
 Aggregation.match(Criteria.where("sex").is("F").and("dept_id").is(2)),
                Aggregation.project("_id", "name", "sex", "dept_id")
        );
		
        //参数一 Aggregation
        //参数二 聚合名
        //参数三 对应的类对象
        AggregationResults<Emp> emp = mongoTemplate.aggregate(aggregation, "emp", Emp.class);
        //调用getMappedResults()方法返回结果集
        List<Emp> mappedResults = emp.getMappedResults();
    }

3.$Match

$match 主要用于筛选符合条件的数据,通常应该把 $match 放在尽量靠前的位置,这时候它会利用索引来优化查询,同时还可以降低后续阶段所需要处理的数据量。示例如下:

Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(查询条件)
);

4.$Project

$project 主要用于定义需要返回的字段,1 代表包含该字段,0 代表不包含。

//定义只返回k1和k2字段的值,注意这里必须填集合中的字段名 
Aggregation.project("k1", "k2") 

5.$group

$group 管道阶段和大多数关系型数据库中的 group by字句功能类似,都是用于分组计算。示例如下:

db.emp.aggregate(
    {		//根据dept_id分组,查询总年龄和平均年龄
			  $group:{
						"_id": "$dept_id",
						"age_sum": {$sum: "$age"},
						"age_avg": {$avg: "$age"}
				}
		}
)

输出

在这里插入图片描述

Java代码

    @Test
    void agg() {
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.group("dept_id").sum("age").as("age_sum").avg("age").as("age_avg"),
                Aggregation.sort(Sort.by(Sort.Order.asc("_id")))
        );
        //第三个参数,指定数据每条数据以什么类型返回,这里显然以Map形式返回。
        AggregationResults<Map> emp = mongoTemplate.aggregate(aggregation, "emp", Map.class);
        List<Map> mappedResults = emp.getMappedResults();
        for (Map mappedResult : mappedResults) {
            System.out.println(mappedResult);
        }
    }

/* 
 *  输出结果
 * 	{_id=1.0, age_sum=36.0, age_avg=18.0} //_id就是 dept_id(这里根据dept_id分组)
 *	{_id=2.0, age_sum=90.0, age_avg=30.0}
 */

参考更多group后的聚合函数

在这里插入图片描述

6.$unwind

$unwind 将文档按照数组中的每一个元素进行拆分

语法格式

{
  $unwind:
    {
      path: <field path>,
      includeArrayIndex: <string>,
      preserveNullAndEmptyArrays: <boolean>
    }
}
  • path用于展开的数组字段
  • includeArrayIndex:用于显示对应元素在原数组的位置信息;
  • preserveNullAndEmptyArrays:如果用于展开的字段值为 null 或空数组时,则对应的文档不会被输出到下一阶段。如果想要输出到下一阶段则需要将该属性设置为 true。示例语句如下:

示例

db.emp.aggregate(
    {
			  $unwind:{
						path: "$likes",
						includeArrayIndex: "arrayIndex",
						preserveNullAndEmptyArrays: true 
				}
		}
)

结果
在这里插入图片描述

注意:如果 preserveNullAndEmptyArrays 的值为 false 或者没有设置,则 5-paul 这条数据不会被输出:

Java代码

    @Test
    void agg() {
        Aggregation aggregation = Aggregation.newAggregation(
               //默认 没有第二个参数,第三个参数为false
                Aggregation.unwind("likes") 
        );
 
        AggregationResults<Emp> emp = mongoTemplate.aggregate(aggregation, "emp", Emp.class);
        List<Emp> mappedResults = emp.getMappedResults();
        for (Emp mappedResult : mappedResults) {
            System.out.println(mappedResult);
        }
    }
/*
Emp{id=1, name='tom', age=13, lists=[basketball], sex='F', deptId=1}
Emp{id=1, name='tom', age=13, lists=[football], sex='F', deptId=1}
Emp{id=2, name='jack', age=14, lists=[games], sex='M', deptId=2}
Emp{id=2, name='jack', age=14, lists=[douyin], sex='M', deptId=2}
Emp{id=3, name='amy', age=23, lists=[code], sex='F', deptId=1}
Emp{id=3, name='amy', age=23, lists=[basketball], sex='F', deptId=1}
Emp{id=4, name='musk', age=42, lists=[car], sex='M', deptId=2}
Emp{id=4, name='musk', age=42, lists=[space], sex='M', deptId=2}
*/

7.$sort&skip&limit

  • $sort 主要用于排序操作,需要注意的是如果可以,应当尽量将该操作放置在管道的第一阶段,从而可以利用索引进行排序,否则就需要使用内存进行排序,这时排序操作就会变得相当昂贵,需要额外消耗内存和计算资源。示例如下
  • $limit 限制返回文档的数量。
  • $skip 跳过一定数量的文档。
db.emp.aggregate(
    [
		{$sort:{age:1}}, //按照年龄升序排序
		{$skip:2}, //跳过前2条数就
		{$limit:2} //显示2条数据
		]
)

Java代码

    @Test
    void agg() {
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.sort(Sort.by(Sort.Order.asc("age"))),
                Aggregation.skip(2),
                Aggregation.limit(2)
        );

        AggregationResults<Emp> emp = mongoTemplate.aggregate(aggregation, "emp", Emp.class);
        List<Emp> mappedResults = emp.getMappedResults();
        for (Emp mappedResult : mappedResults) {
            System.out.println(mappedResult);
        }
    }
/*运行结果
Emp{id=3, name='amy', age=23, lists=[code, basketball], sex='F', deptId=1}
Emp{id=5, name='paul', age=34, lists=[], sex='F', deptId=2}
*/

8.$lookup

8.1关联查询

$lookup 类似与大多数关系型数据库中的 left outer join ,用于实现不同集合之间的连接。其基本的语法如下:

{
   $lookup:
     {
       from: <collection to join>,
       localField: <field from the input documents>,
       foreignField: <field from the documents of the "from" collection>,
       as: <output array field>
     }
}
  • from:指定同一数据库中的集合以进行连接操作;
  • localField:连接集合中用于进行连接的字段;
  • foreignField:待连接集合中用于进行连接的字段;
  • as:指定用于存放匹配文档的新数组字段的名称如果指定的字段已存在,则进行覆盖。
//用dept表的主键_id 连接emp表的外键dept_id
db.dept.aggregate([
   {
      $lookup:
         {
            from: "emp",
            localField: "_id",
            foreignField: "dept_id",
            as: "arr"
        }
   }
]) 

在这里插入图片描述

Java代码

    @Test
    void agg() {
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.lookup("emp", "_id", "dept_id", "arr")
        );
        AggregationResults<Map> emp = mongoTemplate.aggregate(aggregation, "dept", Map.class);
        List<Map> mappedResults = emp.getMappedResults();
        for (Map mappedResult : mappedResults) {
            System.out.println(mappedResult);
        }
    }

/*
{_id=1.0, d_name=研发部, arr=[{_id=1.0, name=tom, age=13.0, likes=[basketball, football], sex=F, dept_id=1.0}, {_id=3.0, name=amy, age=23.0, likes=[code, basketball], sex=F, dept_id=1.0}]}

{_id=2.0, d_name=运维部, arr=[{_id=2.0, name=jack, age=14.0, likes=[games, douyin], sex=M, dept_id=2.0}, {_id=4.0, name=musk, age=42.0, likes=[car, space], sex=M, dept_id=2.0}, {_id=5.0, name=paul, age=34.0, likes=[], sex=F, dept_id=2.0}]}
*/

8.2非关联查询

参考

9.参考

MongoDB聚合

SpringBoot操作MongoDB聚合操作

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shstart7

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值