不知道为啥网上关于java mongo的分组聚合查询都不多,让我等小白无从下手啊,两个接口搞不明白了,丢人啊,接上篇文章多数据源查询,这里主要使用的Aggregation类,这个好像是MongoDB的聚合查询用的?我看网上具体介绍也不多,一下的代码具体需求是:根据前台传过来的时间段来查询这段时间内的数据,当传过来的数据是查询整年数据数则返回每个月的统计数值,也就是返回12条数据,主要统计的是"hours"这个字段,这个字段保存的是工作时长,因为刚进这个项目组就要写接口,所以需求啥的都不是很明确,基本都是摸着石头过河,不懂就问大佬,本人对MongoDB的查询语句目前基本上是一窍不通(需恶补),所以理解起来比较晦涩,路过的大佬还望指点一二,关爱小白、人人有责、水平有限、不喜勿喷啊谈废话伤代码:进入正题
这段代码是上篇文章配置MongoDB多数据源中的TrajectoryServiceImpl查询数据库中的代码
package com.我是***逍遥又自在.service.trajectory;
import com.alibaba.dubbo.config.annotation.Service;
import com.***.config.HashUtil;
import com.***.model.trajectory.Area;
import com.***.model.trajectory.WorkData;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
@Service(
version = "${****.service.version}",
application = "${dubbo.application.id}",
protocol = "${dubbo.protocol.id}",
registry = "${dubbo.registry.id}",
timeout = 10000,
interfaceClass = TrajectoryService.class
)
public class TrajectoryServiceImpl implements TrajectoryService {
@Autowired()
@Qualifier(value = "mongoTemplate")
MongoTemplate mongoTemplate;
@Autowired
@Qualifier(value = "secondMongoTemplate")
MongoTemplate secondMongoTemplate;
@Override
public List selectByDevNum(String devnum) {
Query query = new Query();
// 创建条件对象
query.addCriteria(Criteria.where("devnum").is(devnum));
List ls = mongoTemplate.find(query,Area.class);
return ls;
}
@Override
public List selectByDevnumAndTime(String devnum, String startTime, String endTime) throws ParseException {
Query query = new Query();
List list = new ArrayList<>();
if(StringUtils.isNotBlank(startTime) && StringUtils.isNotBlank(endTime)){
//查询时间段内的
query.addCriteria(Criteria.where("devnum").is(devnum).and("time").gte(startTime).lte(endTime));
list = mongoTemplate.find(query,Area.class);
} else if(StringUtils.isNotBlank(startTime) && !StringUtils.isNotBlank(endTime)){
if(startTime.length() != 4){
//按月查
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = new SimpleDateFormat("yyyy-MM-dd").parse(startTime);
Calendar ca = Calendar.getInstance();//日历对象
ca.setTime(date);
ca.set(Calendar.DAY_OF_MONTH,1);//设置为1号,当前日期既为本月第一天
String firstDay = sdf.format(ca.getTime());
ca.setTime(date);
ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH));
String lastDay = sdf.format(ca.getTime());
query.addCriteria(Criteria.where("devnum").is(devnum).and("time").gte(firstDay).lte(lastDay));
list = mongoTemplate.find(query,Area.class);
} else {
String last = startTime + "-12";
String start = startTime + "-01";
Aggregation aggregation = Aggregation.newAggregation(
//日期条件
Area.class,
Aggregation.match(Criteria.where("devnum").is(devnum).and("time").gte(start).lte(last)),
Aggregation.project("hours","time").andExpression("substr(time,0,7)").as("month"),
Aggregation.group("month").sum("hours").as("hours"),
Aggregation.sort(Sort.Direction.ASC, "_id")
);
AggregationResults aggregate = mongoTemplate.aggregate(aggregation,Area.class,Area.class);
list = aggregate.getMappedResults();
int i = 1;
List newList = new ArrayList<>();
for(Area area : list){
String year = area.getId().substring(0,5);
String mon = area.getId().substring(5,7);
Integer flag = Integer.parseInt(mon);
if(flag > i){
for(int k = i;k < flag;){
Area newArea = new Area();
if(k<10){
newArea.setId(year+"0"+k);
} else {
newArea.setId(year+k);
}
newArea.setHours(0.0);
newArea.setDevnum(devnum);
newArea.setMu(0.0);
newList.add(newArea);
k++;
}
i = flag;
}
newList.add(area);
i++;
}
if(i<13){
for(int f = i;f<13;f++){
Area newArea = new Area();
if(i<10){
newArea.setId(startTime+"-0"+f);
} else {
newArea.setId(startTime+"-"+f);
}
newArea.setHours(0.0);
newArea.setDevnum(devnum);
newArea.setMu(0.0);
newList.add(newArea);
}
}
list = new ArrayList<>();
list = newList;
}
} else {
list = null;
}
return list;
}
@Override
public List querySortedTrajectoryDevInfoBetweenTimes(String devnum, String beginGpsTime, String endGpsTime, int limit, int isWork) {
Criteria criteria = Criteria.where("devnum").is(devnum).and("gpstime").gte(beginGpsTime).lte(endGpsTime);
/* if (isWork == 0) {
criteria = criteria.and("workengineSpeed").is("0");
} else if (isWork > 0) {
criteria = criteria.and("workengineSpeed").gt("0");
}*/
Query query = new Query(criteria);
query.with(new Sort(Sort.Direction.ASC, new String[] { "gpstime" }));
if (limit > 0) {
query.limit(limit);
}
List data = secondMongoTemplate.find(query,WorkData.class,HashUtil.getCollectionName(devnum));
return data;
}
}
//主要是这段代码我不太明白,到目前为止我的理解是以下注释中写的
Aggregation aggregation = Aggregation.newAggregation(
//日期条件
Area.class,
//第一步先根据查询条件查出想要的数据
Aggregation.match(Criteria.where("devnum").is(devnum).and("time").gte(start).lte(last)),
/*第二步从查询出的数据中取出需要处理的数据,我这里是因为库中存的时间格式是“2018-03-08”的格式,
而我要的是根据一年当中12个月来分组,所以这里我要先把数据截取一下,截取到月,也就是substr(time,0,7)
截取time这个字段的数据截取后的时间格式为“2018-03”留作分组按月用,其中用到了三个方法
.project方法.andExpression方法和.as方法.project是要取那几个字段来用.andExpression是把处理后的数据添
添加到处理后的结果中,as方法是为处理后的数据字段加一个别名,注意project方法中的参数,后面
andExpression要处理哪个字段的数据。project中是必须要有的*/
Aggregation.project("hours","time").andExpression("substr(time,0,7)").as("month"),
/*数据处理完以后就是分组操作,group方法中的参数就是上面as取别名的字段的数据参数,这里的意思就是
根据month进行分组,也就是别名之前的那个time字段,不过是已经处理过的数据从time字段的“2018-03-08”
变成了现在month字段的“2018-03”,后面的sum方法就是分组后要计算的数据hours(工作时长)然后as别名
hours,这里的操作室求和,group方法后面我记得网上说还有很多强大的方法,后期我再找找刚大家参考*/
Aggregation.group("month").sum("hours").as("hours"),
/*然后排序,这里有个问题,就是分组获得数据以后个字段有些变化,原先的time变成了id,所有这里排序是
根据id排序的,id就是时间(后期弄明白在补)*/
Aggregation.sort(Sort.Direction.ASC, "_id")
);
/*执行查询,注意这里的mongoTemplate不再是自动装配的mongoTemplate,而是上一篇博文中提到的多数据源*/
AggregationResults aggregate = mongoTemplate.aggregate(aggregation,Area.class,Area.class);
list = aggregate.getMappedResults();
public List querySortedTrajectoryDevInfoBetweenTimes(String devnum, String beginGpsTime, String endGpsTime, int limit, int isWork) {
Criteria criteria = Criteria.where("devnum").is(devnum).and("gpstime").gte(beginGpsTime).lte(endGpsTime);
/* if (isWork == 0) {
criteria = criteria.and("workengineSpeed").is("0");
} else if (isWork > 0) {
criteria = criteria.and("workengineSpeed").gt("0");
}*/
Query query = new Query(criteria);
query.with(new Sort(Sort.Direction.ASC, new String[] { "gpstime" }));
if (limit > 0) {
query.limit(limit);
}
//这里我感觉最重要的是要弄懂MongoTemplate.find(query,WorkData.class,HashUtil.getCollectionName(devnum));的
//这个方法的用法特别是加collectionName参数后的使用
List data = secondMongoTemplate.find(query,WorkData.class,HashUtil.getCollectionName(devnum));
return data;
}
package com.***.config;
public class HashUtil
{
public static int hash(Object key)
{
int h;
return key == null ? 0 : (h = key.hashCode()) ^ h >>> 16;
}
public static int getPartion(Object key)
{
int hash = hash(key);
return hash % 24;
}
public static String getCollectionName(Object key)
{
int hash = hash(key);
hash &= 0x3FF;
return "dev" + hash;
}
}
附数据结构一张:第一次见到数据结构因为之前只做过单个数据源最简单的一个表对应一个实体类,认知当中还是表名跟实体类名对应,当时打开一看的确很懵逼啊