1.应用场景
mongodb数据库有一张职位搜索表(t_position_search),里面存储里一些冗余数据(存在一些数据除了id不同其余字段都相同的数据),其中有一个字段是postId,我的需求是在多个相同postId的数据中我只取其中一条(任意一条无所谓,因为相同postId的数据中除了id不同其余字段都相同,我不需要id字段,所以取任意一条无所谓),此时就需要用到mongoTemplate的分组语句。
2.Dao最终代码
public PageForm queryForPage(QueryForm queryForm,
String companyId,
Set<String> suitOrgCodeSet,
String postKey,
String postName,
Integer recruitType,
String workPlaceCode,
String postTypeCode,
String orgCode,
String siteCode,
String salaryCode,
String educationCode,
Date publishBeginDate) {
// 构建查询条件
Criteria criteria = Criteria.where("companyId").is(companyId);
// 适用机构列表
List<Criteria> criterias = new ArrayList<>();
for(String suitOrgCode:suitOrgCodeSet){
Criteria newCriteria = Criteria.where("orgCode").regex(suitOrgCode + "($|/.*)");
criterias.add(newCriteria);
}
Criteria[] result = criterias.toArray(new Criteria[criterias.size()]);
criteria.orOperator(result);
// 招聘类型
criteria.and("recruitType").is(recruitType);
// 职位名称(模糊查询)
if(StringUtils.isNotBlank(postName)){
criteria.and("externalPostName").regex(".*" + postName + ".*");
}
// 职位关键字(模糊查询)
if(StringUtils.isNotBlank(postKey)){
criteria.and("postKeySearch").regex(".*" + postKey + ".*");
}
// 学历
if(StringUtils.isNotBlank(educationCode)){
criteria.and("educationCode").is(educationCode);
}
// 工作地点
if(StringUtils.isNotBlank(workPlaceCode)){
// 数组中元素的具体查询
//criteria.and("workPlaceCodeList").elemMatch(new Criteria().in(workPlaceCode));
// 数组中元素的正则匹配的模糊查询
criteria.and("workPlaceCodeList").elemMatch(new Criteria("$regex").is(workPlaceCode + "($|/.*)"));
}
// 职位类型(匹配当前职位类型及其以下职位类型)
if(StringUtils.isNotBlank(postTypeCode)){
criteria.and("postTypeCode").regex(postTypeCode + "($|/.*)");
}
// 所属机构(匹配当前机构及其以下机构)
if(StringUtils.isNotBlank(orgCode)){
criteria.and("orgCode").regex(orgCode + "($|/.*)");
}
// 站点
if(StringUtils.isNotBlank(siteCode)){
criteria.and("siteCodeList").elemMatch(new Criteria().in(siteCode));
}
// 薪酬范围
if(StringUtils.isNotBlank(salaryCode)){
criteria.and("salaryCode").is(salaryCode);
}
// 发布时间:终止日期为当前时间
if(publishBeginDate != null){
criteria.andOperator(Criteria.where("publishFirstDate").gte(publishBeginDate), Criteria.where("publishFirstDate").lt(new Date()));
}
// 分组查询数据
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(criteria), //查询条件
Aggregation.group("postId") //分组条件
.first("postId").as("postId")
.first("top").as("top")
.first("publishFirstDate").as("publishFirstDate")
.first("orgCode").as("orgCode"),
Aggregation.sort(new Sort(Sort.Direction.DESC,"publishFirstDate")) // 排序
.and(new Sort(Sort.Direction.DESC,"publishFirstDate")),
Aggregation.skip((queryForm.getCurrentPage() - 1) * queryForm.getPageSize()),//跳到第几个开始
Aggregation.limit(queryForm.getPageSize())//查出多少个数据
);
AggregationResults<PositionSearchPo> results =
mongoTemplate.aggregate(aggregation,"t_position_search", PositionSearchPo.class);
List<PositionSearchPo> list = results.getMappedResults();
// 分组查询分组后的总记录数
Aggregation aggregation2 = Aggregation.newAggregation(
Aggregation.match(criteria), //查询条件
Aggregation.group("postId") //分组条件
);
AggregationResults<PositionSearchPo> results2 =
mongoTemplate.aggregate(aggregation2,"t_position_search", PositionSearchPo.class);
int dataCount = results2.getMappedResults().size();
PageForm pageForm = new PageForm();
pageForm.setCurrentPage(queryForm.getCurrentPage());
pageForm.setPageSize(queryForm.getPageSize());
pageForm.setDataCount(dataCount);
pageForm.setPageData(list);
return pageForm;
}
3.分析分组查询
// 分组查询数据
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(criteria), //查询条件
Aggregation.group("postId") //分组条件
.first("postId").as("postId")
.first("top").as("top")
.first("publishFirstDate").as("publishFirstDate")
.first("orgCode").as("orgCode"),
Aggregation.sort(new Sort(Sort.Direction.DESC,"top")) // 排序
.and(new Sort(Sort.Direction.DESC,"publishFirstDate")),
Aggregation.skip((queryForm.getCurrentPage() - 1) * queryForm.getPageSize()),//跳到第几个开始
Aggregation.limit(queryForm.getPageSize())//查出多少个数据
);
AggregationResults<PositionSearchPo> results = mongoTemplate.aggregate(aggregation,"t_position_search", PositionSearchPo.class);
List<PositionSearchPo> list = results.getMappedResults();
Aggregation.match(criteria) 是添加查询条件。
Aggregation.group("postId") 是添加分组字段。后面的 first("postId").as("postId") 代表需要查询的字段映射到实体里的名称,
因为我需要查出这些字段,且后面的排序也需要这些字段,所以必须映射出来,否则如果不添加这些映射,使用group方法,查询出来的实体类中的字段只有postId字段,而且postId的值还被映射到实体中的id字段上去了。也就是说,如果没有后面的first方法,查询出来的实体里面只有id有值,而且这个id的值也不是数据库中id的值,而是postId的值,其余的字段都是没有值的,而且后面添加的排序方法也会报错,因为根本没有查询出来top和publishFirstDate字段。所以可以把需要查询的字段,以first的方式映射出来。
我搜了一下Aggregation.project方法,这个方法是查询出指定字段,但是我尝试和group方法一起用的时候,根本不能查询出除了id以外其他的字段,所以根本就没有用,也可能是我没找到对的使用方法,所以我只能放弃使用project方法了。
还有,如果没有group分组,当然也可以不使用project方法,查询出来的实体包含所有的字段信息,所以我猜想这个group方法里默认查出的字段只有分组的这个字段。
Aggregation.sort(new Sort(Sort.Direction.DESC,"top")) .and(new Sort(Sort.Direction.DESC,"publishFirstDate")),这是根据多个字段进行排序。
因为要查询出总的数据条数,所以重复查询了两次,第一次是根据页码查询出当前页的数据,第二次是查询出总的数据条数
4.分析mogodbTemplate别的查询语句
如果查询条件中有集合,而且是或的关系
// 适用机构列表
List<Criteria> criterias = new ArrayList<>();
for(String suitOrgCode:suitOrgCodeSet){
Criteria newCriteria = Criteria.where("orgCode").regex(suitOrgCode + "($|/.*)");
criterias.add(newCriteria);
}
Criteria[] result = criterias.toArray(new Criteria[criterias.size()]);
criteria.orOperator(result);
如果数据库中的记录中,某一个字段是数组,查询条件中数值精准匹配到这个数组中的其中一个元素
// 工作地点
if(StringUtils.isNotBlank(workPlaceCode)){
// 数组中元素的具体查询
criteria.and("workPlaceCodeList").elemMatch(new Criteria().in(workPlaceCode));
}
如果数据库中的记录中,某一个字段是数组,查询条件中数值模糊匹配到这个数组中的其中一个元素
// 工作地点
if(StringUtils.isNotBlank(workPlaceCode)){
// 数组中元素的正则匹配的模糊查询
criteria.and("workPlaceCodeList").elemMatch(new Criteria("$regex").is(workPlaceCode + "($|/.*)"));
}
范围查询
// 发布时间:终止日期为当前时间
if(publishBeginDate != null){
criteria.andOperator(Criteria.where("publishFirstDate").gte(publishBeginDate), Criteria.where("publishFirstDate").lt(new Date()));
}
gte是大于或等于,gt是大于,lte是小于或等于,lt是小于