关于mongoTemplate的联表查询,之前的内容没有描述清楚,这次清空了重写。
案例关系:org通过 orgId一对多 关联task,需要查出每个org和其最新的一个task
org ——orgId——> task1、task2、…
代码:
LookupOperation lookup = LookupOperation.newLookup()
.from("task") //次表
.localField("orgId") //主表关联字段
.foreignField("orgId") //次表关联字段
.as("link"); //临时集合别名
Aggregation aggregation = Aggregation.newAggregation(
//主表条件
Aggregation.match(Criteria.where("isDel").ne(1)),
//联表
lookup,
//次表条件
Aggregation.unwind("link"),
Aggregation.match(Criteria.where("link.isDel").ne(1)),
Aggregation.sort(Sort.by(Sort.Order.desc("link.createTime"))),
Aggregation.group("task.orgId")
.first("link.title").as("title")
.first("orgId").as("orgId")
.first("orgName").as("orgName")
.first("link.createTime").as("createTime"),
Aggregation.sort(Sort.by(Sort.Order.desc("createTime"),Sort.Order.desc("orgId"))),
Aggregation.project("orgId","title","createTime")
);
List<Org> orgs = mongoTemplate.aggregation(aggregation,Org.class).getMappedResults();
接下来根据代码分析:
-
首先是主表条件,就是对最后
mongoTemplate.aggregation(aggregation,Org.class).getMappedResults()
中Org.Class
对应的表直接进行操作,这一步的结果大致如下:[ { "orgId":"", "orgName":"", "createTime":"" }, .... ]
-
Lookup进行联表操作
LookupOperation lookup = LookupOperation.newLookup() .from("task") //次表 .localField("orgId") //主表关联字段 .foreignField("orgId") //次表关联字段 .as("link"); //临时集合别名
这一步是把次表中满足关联条件(关联字段相等,
类似于sql的inner join
)的数据查出来作为一个数组,用as
指定的别名嵌入到上一步的操作中,此时的结果大致如下:[ { "orgId":"", "orgName":"", "createTime":"", "link":[ { "taskId":"", "orgId":"", "title":"", "createTime":"" }, ... ] }, .... ]
-
次表条件,是将
步奏2
的结果进行操作。由于联表的结果是个内嵌的数组,如果需要的是一对一的关系,需要进行Aggregation.unwind()
再进行操作。例如此处要取出每个org最新的一个task://次表条件,对步奏2的结果集进行操作 Aggregation.unwind("link"), //拆分link Aggregation.match(Criteria.where("link.isDel").ne(1)), //过滤条件 Aggregation.sort(Sort.by(Sort.Order.desc("link.createTime"))), //创建时间倒序,在下一步分组中取出排序后的首位
此时的结果集:
[ { "orgId":"o1", "orgName":"", "createTime":"", "link":{ "taskId":"t1", "orgId":"o1", "title":"tt1", "createTime":"time4" } }, { "orgId":"o1", "orgName":"", "createTime":"", "link":{ "taskId":"t2", "orgId":"o1", "title":"tt2", "createTime":"time3" } }, { "orgId":"o2", "orgName":"", "createTime":"", "link":{ "taskId":"t3", "orgId":"o2", "title":"tt3", "createTime":"time2" } }, { "orgId":"o2", "orgName":"", "createTime":"", "link":{ "taskId":"t4", "orgId":"o2", "title":"tt4", "createTime":"time1" } }, .... ] //其中,time1<time2<time3<time4
再在此基础上进行分组:
... //分组操作,取首位数据,并指定需要字段的别名(分组字段的值会默认放在"_id"上) Aggregation.group("task.orgId") .first("link.title").as("title") .first("orgId").as("orgId") .first("orgName").as("orgName") .first("link.createTime").as("createTime"), Aggregation.project("orgId","title","createTime")
最后的结果集大致如下:
[ { "orgId":"o1", "title":"tt1", "createTime":"time4" }, { "orgId":"o2", "title":"tt2", "createTime":"time2" }, ]
总结
- 在LookupOperation前的操作,针对主表操作
- LookupOperation,指定关联doc,关联字段,和联表结果集别名。并将结果集以数组形式嵌入到**<1>**的对应结果中。
此时整个结果集只会剩下存在关联关系的数据(inner join) - 在LookupOperation后的操作,针对<2>的结果集进行操作