Spring Boot 整合——MongoDB整合3(MongoDB聚合操作)
文章前面
关于版本
依赖 | 版本 |
---|---|
springboot | 2.0.8.RELEASE |
mongodb | 4.0.14 |
本内容只是为了介绍mongodb最基础的使用以及配置,作为一个知名的数据库,其存在相当多的高级用法,展开来介绍内容会相当多,当然本人并非相关领域的大神,下面内容只不过整理了自己日常使用的一些积累。是对自己经验的积累,也希望能帮助后来的同学
关于项目
本内容也是我尝试整理工作中接触过各种工具在springboot中使用的方法。下面介绍的所有方法都已经提供了测试用例。因为每个例子涉及代码较多,所以文章中只贴出了部分代码。全部的代码在这里:https://gitee.com/daifyutils/springboot-samples。
聚合管道操作
MongoTemplate提供了aggregate方法来实现对数据的聚合操作。其核心逻辑在于接受一个TypedAggregation
参数,此参数定义了聚合操作的具体限制语句。
@Override
public <O> AggregationResults<O> aggregate(TypedAggregation<?> aggregation, Class<O> outputType) {
return aggregate(aggregation, operations.determineCollectionName(aggregation.getInputType()), outputType);
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.MongoOperations#aggregate(org.springframework.data.mongodb.core.aggregation.TypedAggregation, java.lang.String, java.lang.Class)
*/
@Override
public <O> AggregationResults<O> aggregate(TypedAggregation<?> aggregation, String inputCollectionName,
Class<O> outputType) {
Assert.notNull(aggregation, "Aggregation pipeline must not be null!");
AggregationOperationContext context = new TypeBasedAggregationOperationContext(aggregation.getInputType(),
mappingContext, queryMapper);
return aggregate(aggregation, inputCollectionName, outputType, context);
}
聚合管道支持操作
MongoTemplate提供的aggregate方法,实际上是mongodb的aggregate()的JAVA版。而实际上MongoTemplate提供的aggregate方法也是生成mongodb的aggregate()的表达式来进行最终的查询。
aggregate你可以认为是一个管道,当MongoDB的文档经过一个管道处理之后处理后的数据会传递给下一个管道来进行处理。这就对管道的使用产生两个影响:1.管道处理是顺序的,相同的管道内容不同的执行顺序会产生不同的结果。2.管道只能处理被之前管道处理过后的数据。
mongodb提供的aggregate()
聚合管道操作
下面是基于聚合管道mongodb提供的可操作的内容
支持的操作 | java接口 | 说明 |
---|---|---|
$project | Aggregation.project | 修改输入文档的结构。 |
$match | Aggregation.match | 用于过滤数据 |
$limit | Aggregation.limit | 用来限制MongoDB聚合管道返回的文档数 |
$skip | Aggregation.skip | 在聚合管道中跳过指定数量的文档 |
$unwind | Aggregation.unwind | 将文档中的某一个数组类型字段拆分成多条 |
$group | Aggregation.group | 将集合中的文档分组,可用于统计结果 |
$sort | Aggregation.sort | 将输入文档排序后输出 |
$geoNear | Aggregation.geoNear | 输出接近某一地理位置的有序文档 |
聚合内容操作
下面是基于聚合操作(Aggregation.group),mongodb提供可选的表达式
聚合表达式 | java接口 | 说明 |
---|---|---|
$sum | Aggregation.group().sum(“field”).as(“sum”) | 求和 |
$avg | Aggregation.group().avg(“field”).as(“avg”) | 求平均 |
$min | Aggregation.group().min(“field”).as(“min”) | 获取集合中所有文档对应值得最小值 |
$max | Aggregation.group().max(“field”).as(“max”) | 获取集合中所有文档对应值得最大值 |
$push | Aggregation.group().push(“field”).as(“push”) | 在结果文档中插入值到一个数组中 |
$addToSet | Aggregation.group().addToSet(“field”).as(“addToSet”) | 在结果文档中插入值到一个数组中,但不创建副本 |
$first | Aggregation.group().first(“field”).as(“first”) | 根据资源文档的排序获取第一个文档数据 |
$last | Aggregation.group().last(“field”).as(“last”) | 根据资源文档的排序获取最后一个文档数据 |
聚合管道的实际使用
Group聚合操作
@Override
public List<GroupVo> getAggGroup() {
GroupOperation noRepeatGroup = Aggregation.group( "userId","type")
.count().as("num")
.sum("totalProduct").as("count");
TypedAggregation<Order> noRepeatAggregation =
Aggregation.newAggregation(Order.class,noRepeatGroup);
AggregationResults<GroupVo> noRepeatDataInfoVos = mongoTemplate.aggregate(noRepeatAggregation, GroupVo.class);
List<GroupVo> noRepeatDataList = noRepeatDataInfoVos.getMappedResults();
System.out.println(JSON.toJSONString(noRepeatDataList));
return noRepeatDataList;
}
上面例子中对order
集合中的userId
和type
进行分组,使用count
获取总数并映射到num
字段中,对totalProduct
字段进行求和并映射到count
字段中。在所有的Group聚合操作中,除了count
之外,其他操作使用格式基本上都是相同的。其在JAVA中的调用都是使用下面格式
GroupOperation noRepeatGroup = Aggregation.group( {分组字段1},{分组字段2})
.count().as({count结果映射的字段})
.sum({需要进行sum的字段}).as({sum结果映射的字段})
project操作
@Override
public List<GroupVo> getAggProject() {
// 重排的
GroupOperation noRepeatGroup = Aggregation.group( "userId","type")
.count().as("num")
.sum("totalProduct").as("count");
Field field = Fields.field("num2", "num");
ProjectionOperation project = Aggregation.project("userId","type")
.andInclude(Fields.from(field));
TypedAggregation<Order> noRepeatAggregation =
Aggregation.newAggregation(Order.class,noRepeatGroup,project);
AggregationResults<GroupVo> noRepeatDataInfoVos = mongoTemplate.aggregate(noRepeatAggregation, GroupVo.class);
List<GroupVo> noRepeatDataList = noRepeatDataInfoVos.getMappedResults();
System.out.println(JSON.toJSONString(noRepeatDataList));
return noRepeatDataList;
}
project主要作用就是调整文档的字段内容。比如上面内容中获取数据条目数最开始映射到num字段中,但是在下面Field field = Fields.field("num2", "num")
这里将num的映射转为了num2的映射。这个方法在后续使用lookup进行联表查询的时候会非常有用。因为正常进行联表查询的时候被连接表会作为结果集中的子集出现,而使用project可以将子集数据作为文档的同一层级数据展示出来。
关于match
,unwind
,sort
我会在后面的联表查询、分组去重内容里面来介绍
Bucket操作
在使用聚合管道的时候,可以使用Aggregation.bucket
将数据根据某些范围分为多个桶,或者使用Aggregation.bucketAuto
将数据分为指定数量的桶。
- Aggregation.bucket
Aggregation.bucket方法允许使用者设置一个字段,以及一个多段的查询区间。mongodb将根据这个字段的内容以及设置的分组区间生成多个数据桶。我们可以获取每个桶的聚合结果。下面的例子中就是将Order集合中的数据根据type字段的值分为[0,1),[1,2),[2,3),[3,other)四组。
@Override
public List<BucketVo> getAggBucket() {
BucketOperation bucketOperation =
// 分组的字段
Aggregation.bucket("type")
// 根据范围进行分组
.withBoundaries(0,1,2,3)
// 默认分组
.withDefaultBucket("other")
// 求总
.andOutput("_id").count().as("count")
// 求和
.andOutput("totalProduct").sum().as("sum")
// 求平均
.andOutput("totalMoney").avg().as("avg");
TypedAggregation<Order> newAggregation =
Aggregation.newAggregation(Order.class, bucketOperation);
AggregationResults<BucketVo> noRepeatDataInfoVos2 =
mongoTemplate.aggregate(newAggregation, BucketVo.class);
return noRepeatDataInfoVos2.getMappedResults();
}
字段介绍
- bucket:需要进行分桶依据的字段
- withBoundaries:分桶区间的范围内容,需要注意的是这个范围是包含前一个条件的值不包含后一个条件的值
- withDefaultBucket:所有没被设定范围统计到的数据会被放入到other这个桶中,其中other是这个桶的id
- andOutput:需要输出的内容,一般是针对某个字段的聚合结果
- Aggregation.bucketAuto
bucketAuto是指定的参数和字段,根据对应字段的内容,将数据平均分配为指定数量的桶。比如下面例子中数据根据type字段中的值分成2组
@Override
public List<BucketVo> getAggBucketAuto() {
// 分组的字段
BucketAutoOperation autoOperation = Aggregation.bucketAuto("type", 2)
// 求总
.andOutput("_id").count().as("count")
// 求和
.andOutput("totalProduct").sum().as("sum")
// 求平均
.andOutput("totalMoney").avg().as("avg");
TypedAggregation<Order> newAggregation =
Aggregation.newAggregation(Order.class, autoOperation);
AggregationResults<BucketVo> noRepeatDataInfoVos2 =
mongoTemplate.aggregate(newAggregation, BucketVo.class);
return noRepeatDataInfoVos2.getMappedResults();
}
字段介绍
-
bucketAuto: 需要设置进行分桶依据的字段,以及需要分的桶数量
-
andOutput:需要输出的内容,一般是针对某个字段的聚合结果
个人水平有限,上面的内容可能存在没有描述清楚或者错误的地方,假如开发同学发现了,请及时告知,我会第一时间修改相关内容,也希望大家看在这个新春佳节只能宅到家中埋头苦逼的码代码的情况下,能给我点一个赞。你的点赞就是我前进的动力。在这里也祝大家新春快乐。
上一篇: JJWT工具类
推荐阅读
-
详解spring boot jpa整合QueryDSL来简化复杂操作
-
Spring + Spring Boot + MyBatis + MongoDB的整合教程
-
详解MongoDB和Spring整合的实例代码
-
详解spring boot jpa整合QueryDSL来简化复杂操作
-
如何优雅的进行Spring整合MongoDB详解
-
轻轻松松学习SpringBoot2:第二十五篇: Spring Boot和Mongodb整合(完整版)
-
MongoDB安装与Spring整合
-
Spring Boot 整合 MongoDB的示例
-
spring boot整合mybatis使用c3p0数据源连接mysql
-
Spring MVC与Mongodb整合开发实例