mongoTemplate支持多表联查 排序 条件筛选 分页 去重分组

该文章展示了如何使用Java进行MongoDB的连表查询,通过对school和class两个表进行连接,根据特定字段进行筛选(如学校名为新民小学,教师名为高老师),并实现排序和分页功能。代码中涉及了LookupOperation、AddFieldsOperation、Aggregation等操作,以及数据类型转换和条件判断。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述

说明

需求:
列表展示需要对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}{咱们来日方长,有缘江湖再见,告辞!} 咱们来日方长,有缘江湖再见,告辞!

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值