说明
需求:
列表展示需要对mongo的两表进行连表查询,且根据两个不同的表中指定字段去排序分页展示,其中包含对两个表不同条件的筛选。
以下案例:
school主表和class次表,查询school里面为新民小学,并且名字叫高老师的所有班级,返回班级里面的所有学生的姓名、年龄。案例简单看看,主要看代码技术点。
代码
数据总条数
public long getTotal(String teacherName, String startTime, String endTime) {
LookupOperation lookup = LookupOperation.newLookup()
//次表名称
.from("class")
//主表关联字段
.localField("classId")
//次表关联字段
.foreignField("classId")
//临时表明 主要是给次表用
.as("er");
//数据类型转换,classId在一个表是string,另一个表是objectId类型,如果没有转换需求可忽略
AddFieldsOperation addFieldsOperation = AddFieldsOperation
.addField("classId")
.withValue(ConvertOperators.ToObjectId.toObjectId("$classId")).build();
//次表查询条件
Criteria criteria = Criteria.where("er.teacher").is("高老师");
if (StringUtils.isNotBlank(startTime) && StringUtils.isNotBlank(endTime)) {
criteria.and("er.createTime").gte(dateToISODate(strToDateLong(startTime))).lte(dateToISODate(strToDateLong(endTime)));
}
Aggregation countAgg = Aggregation.newAggregation(
//主表查询条件
Aggregation.match(Criteria.where("schoolName").is("新民小学")),
addFieldsOperation,
lookup,
//lookup以下是次表查询条件和分组
Aggregation.unwind("er"),
Aggregation.match(criteria),
Aggregation.group("_id:null").count().as("count")
);
//school是主表名称
AggregationResults<Map> resultCount = mongoTemplate.aggregate(countAgg, "school", Map.class);
List<Map> countList = resultCount.getMappedResults();
long count = 0L;
if (countList.size() > 0) {
// 拿到总条数,可以用于业务分页计算
count = Long.parseLong(countList.get(0).get("count").toString());
}
return count;
}
数据总体data
public List<ClassVo> infoData(String teacherName, String startTime, String endTime, Integer pageNum, Integer pageSize) {
LookupOperation lookup = LookupOperation.newLookup()
//次表名称 班级
.from("class")
//主表关联字段
.localField("classId")
//次表关联字段
.foreignField("classId")
//临时表明 主要是给次表用
.as("er");
//数据类型转换,classId在一个表是string,另一个表是objectId类型,如果没有转换需求可忽略
AddFieldsOperation addFieldsOperation = AddFieldsOperation
.addField("classId")
.withValue(ConvertOperators.ToObjectId.toObjectId("$classId")).build();
//次表查询条件
Criteria criteria = Criteria.where("er.teacher").is(teacherName);
if (StringUtils.isNotBlank(startTime) && StringUtils.isNotBlank(endTime)) {
criteria.and("er.createTime").gte(dateToISODate(strToDateLong(startTime))).lte(dateToISODate(strToDateLong(endTime)));
}
Aggregation countAgg = Aggregation.newAggregation(
Aggregation.match(Criteria.where("schoolName").is("新民小学")),
addFieldsOperation,
lookup,
Aggregation.unwind("er"),
Aggregation.match(criteria),
//主表字段
Aggregation.project("classId", "status")
//次表字段都要用【er.】才能获取到
.andInclude("er._id", "er.tearcher", "er.student.name", "er.student.age"),
//根据主表状态和次表年龄降序排序
Aggregation.sort(Sort.Direction.DESC, "status", "age"),
//去重 连表查询避免不了一对多关系 会查出重复数据可以用group对id进行分组去重 .first可以理解为返回的字段as为返回的别名,这里可以理解为sql返回后的最终字段 如果要返回学生名称 不需要用er.student.name 直接name字段获取
Aggregation.group("_id").first("_id").as("id")
.first("tearcher").as("tearcher")
.first("name").as("name")
.first("age").as("age"),
//分页
Aggregation.skip((pageNum - 1) * pageSize),
Aggregation.limit(pageSize)
);
//school是主表名称
AggregationResults<ServerRecordVo> resultCount = mongoTemplate.aggregate(countAgg, "school", ServerRecordVo.class);
List<ServerRecordVo> vos = resultCount.getMappedResults();
return vos;
}
就先说到这
\color{#008B8B}{ 就先说到这}
就先说到这
在下
A
p
o
l
l
o
\color{#008B8B}{在下Apollo}
在下Apollo
一个爱分享
J
a
v
a
、生活的小人物,
\color{#008B8B}{一个爱分享Java、生活的小人物,}
一个爱分享Java、生活的小人物,
咱们来日方长,有缘江湖再见,告辞!
\color{#008B8B}{咱们来日方长,有缘江湖再见,告辞!}
咱们来日方长,有缘江湖再见,告辞!