SpringBoot整合Mongodb(三) 使用MongoTemplate进行连表查询

由于在实际开发项目中,突然涉及到了需要Mongodb 进行连表操作的业务,所以我在私下进行了一波学习。

服务器中 mongodb数据库安装以及密码设置请见:Centos7 使用Yum源安装MongoDB4.2版本数据库(补:密码配置)

springboot-mongodb 单数据源的的CRUD 以及批量操作请见:SpringBoot整合MongoDB(一)

使用多数据源以及Aggregation 管道对mongo 进行聚合函数操作(分组,统计,分页等等)请见:SpringBoot整合MongoDB(二)多数据源配置,Aggregation管道使用

使用MongoTemplate连表查询主要是使用LookupOperation 确定主表 从表 主表关联字段以及从表关联字段等。

话不多说,直接开战。

(一)数据准备

本文中暂时学习了 一对一 (两张表/多张表) 一对多(多对一) ,我呢,总共是准备了4张表

学生表

@Data
@Document(collation = "student")
@NoArgsConstructor
@AllArgsConstructor
public class Student implements Serializable {/*** 自定义mongo主键 加此注解可自定义主键类型以及自定义自增规则*  若不加 插入数据数会默认生成 ObjectId 类型的_id 字段*  org.springframework.data.annotation.Id 包下*  mongo库主键字段还是为_id 。不必细究(本文实体类中为id)*/@Idprivate Long id;private String username;/*** 关联班级ID*/private Long classId;
}

班级表

@Data
@Document(collation = "studentClass")
@NoArgsConstructor
@AllArgsConstructor
public class StudentClass implements Serializable {@Idprivate Long id;private String className;/**关联学校*/private Long schoolId;
}

学校表

@Data
@Document(collation = "school")
@NoArgsConstructor
@AllArgsConstructor
public class School implements Serializable {@Idprivate Long id;private String schoolName;/**关联城市ID*/private Long cityId;
}

城市表

@Data
@Document(collation = "city")
@NoArgsConstructor
@AllArgsConstructor
public class City implements Serializable {@Idprivate Long id;private String cityName;}

无关数据真实性以及业务逻辑性设计

一个学生对应一个班级(多个学生对应一个班级)无所谓,代码主要是进行连表测试。

添加测试数据

    public JsonReturn addData() {List<Student> students = Arrays.asList(new Student(1L, "小明", 1L),new Student(2L, "小红", 2L),new Student(3L, "小菜", 2L));List<StudentClass> studentClasses = Arrays.asList(new StudentClass(1L, "三年级一班", 1L),new StudentClass(2L, "三年级二班", 2L));List<School> schools = Arrays.asList(new School(1L, "旺仔小学", 1L),new School(2L, "蒙牛小学", 1L));City city = new City();city.setId(1L);city.setCityName("希望市");try {mongoTemplate.insertAll(students);mongoTemplate.insertAll(studentClasses);mongoTemplate.insertAll(schools);mongoTemplate.save(city);HashMap<String, Object> map = new HashMap<>(4);map.put("student", students);map.put("studentClass", studentClasses);map.put("schools", schools);map.put("city", city);return JsonReturn.buildSuccess(map);} catch (Exception e) {e.printStackTrace();return JsonReturn.buildFailure("error");}}

(二)两表联查

学生表与班级表进行联查 以血学生为主表(即查询第一视角) 多对一查询

public JsonReturn MoreToOne() {LookupOperation lookup = LookupOperation.newLookup()//从表(关联的表).from("studentClass")//主表中与从表相关联的字段.localField("classId")//从表与主表相关联的字段.foreignField("_id")//查询出的从表集合 命名.as("class");Aggregation agg = Aggregation.newAggregation(lookup);try {AggregationResults<Map> studentAggregation = mongoTemplate.aggregate(agg, "student", Map.class);return JsonReturn.buildSuccess(studentAggregation.getMappedResults());} catch (Exception e) {e.printStackTrace();return JsonReturn.buildFailure("error");}}

需要注意的是: .as是查询出的从表数据结果集的名字 ,类似于mysql 中 在一个实体类中要设置一个关联对象类型字段 那么我们获取其相关关联对象信息的时候只需要.关联对象.字段 即可 我们mongodb 获取关联对象信息则是.as取得名字.字段名

mongoTemplate.aggregat()中 表选择必须是主表(以谁为第一视角则谁当主表),我这里以student为主表 那么我查询后信息的第一视角则为Student

那么这只是普通的查询,并无任何搜索条件,我们如何根据条件进行结果筛选呢?

一样的使用match即可,主表条件与原来一致,使用我们只是需要关心,如何根据从表的数据进行查询。

那么,我们就来设计一下,主表从表查询条件,比如根据班级Id 或者学生Id 进行查询

定义一个接口,入参可选择学生id 或者班级Id

 public JsonReturn MoreToOne(Long studentId, Long classId) {LookupOperation lookup = LookupOperation.newLookup()//关联的从表名字.from("studentClass")//主表中什么字段与从表相关联.localField("classId")//从表中的什么字段与主表相关联.foreignField("_id")//自定义的从表结果集名  与主表关联的数据归于此结果集下.as("class");Criteria criteria = new Criteria();if (studentId != null) {//主表可能选择的条件criteria.and("_id").is(studentId);}//从表可能选择的条件if (classId != null) {//class 为我之前定义的从表结果集名criteria.and("class._id").is(classId);}//将筛选条件放入管道中MatchOperation match = Aggregation.match(criteria);Aggregation agg = Aggregation.newAggregation(lookup, match);try {AggregationResults<Map> studentAggregation = mongoTemplate.aggregate(agg, "student", Map.class);return JsonReturn.buildSuccess(studentAggregation.getMappedResults());} catch (Exception e) {e.printStackTrace();return JsonReturn.buildFailure("error");}}

查询学生ID 为2的数据

查询班级ID 为2的数据,可以看到 小红 和小菜都是班级Id为2中的学生,因为我这里主表是学生啊,所以会有两条数据,如果我主表是以班级为查询那么就会变为一对多查询了,就只会有一条数据,其中students列表中包含小红和小明罢了

注意**:从表条件不能直接根据从表的列名 而是要通过(从表结果集名字**.**列名)作为要查询的列

既然,数据我们都获取到了,那么我们拿一下从表数据试一试?

比如在elementui中 的table组件中,在clomn中展示从表数据呢

先在控制台打印一波从表数据

http://localhost:8080/mongo/moreToOne?studentId=2 我们吧查询条件还是设为学生id为2


发现明明只是一条数据,为什么还是要给我结果集设为一个数组呢,那么取从表数据不是要 结果集[索引].字段 了?
这显然不是我们想要的结果 ,看了很久,终于发现了,可以使用Aggregation.unwind()方法来拆分一个结果集
官方说明
$unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。

那么我们在原来aggregation管道中加入unwind

        //将筛选条件放入管道中MatchOperation match = Aggregation.match(criteria);Aggregation agg = Aggregation.newAggregation(lookup, match,Aggregation.unwind("class"));

我们这样写呢,就会将class 从表结果集拆分了

我们在次来查询所有,与之前相比,发现class数组中的索引,已经没有了
未使用unwind之前

使用unwind后

一对多

一个班级 对应多个学生

public JsonReturn manyToOne() {LookupOperation lookupOperation = LookupOperation.newLookup()//关联的表.from("student")//主表以什么字段与从表相关联的.localField("_id")//从表关联的字段.foreignField("classId")//定义的从表数据查询出的结果结合.as("studentList");Aggregation agg = Aggregation.newAggregation(lookupOperation, Aggregation.unwind("studentList"));try {AggregationResults<Map> studentAggregation = mongoTemplate.aggregate(agg, "studentClass", Map.class);return JsonReturn.buildSuccess(studentAggregation.getMappedResults());} catch (Exception e) {e.printStackTrace();return JsonReturn.buildFailure("error");}}

因为我们使用了unwind来拆分studentList 学生从表结果集 那么结果集数组就会拆成一个个对象 如果原来结果集中有多个数据那么也会根据主表数据来显示出多条数据

可以看到 三年级二班数据中的小菜和小红已经根据主表 拆分成了两条数据了 如果不使用unwind 结果又会是这样

(三)多表联查

从学生关联班级 班级关联学校 学校关联城市

多表联查 需要注意 可能当前的从表又是下一个关联关系的主表 ,那么主表中关联从表的字段就不能直接写明了,要通过之前设为的结果集.字段

需要注意的点以及代码注释我已经写得很详细了,当然我这里没有写unwind了,写出来 效果与之前一致,拆分数组为一个个具体的对象

    /*** 多表一对一  以Student为主表(第一视角)** @return*/@Overridepublic JsonReturn moreTableOneToOne() {//学生关联班级LookupOperation lookupOne = LookupOperation.newLookup()//关联的从表  (班级).from("studentClass")//主表中什么字段与从表(班级)关联.localField("classId")//从表(班级)什么字段与主表关联字段对应.foreignField("_id")//从表结果集.as("class");//班级关联学校  那么此时 这两者之间 班级又是 学校的主表 班级还是学生的从表LookupOperation lookupTwo = LookupOperation.newLookup()//班级关联的从表(学校).from("school")//主表中什么字段与从表(学校)关联  因为班级也是student从表  且已经设了结果集为class  那么主表字段也只能结果集.字段.localField("class.schoolId").foreignField("_id").as("school");//学校关联城市 两者之前 学校则为城市二者关联关系中的主表  学校还是班级的从表LookupOperation lookupThree = LookupOperation.newLookup()//学校关联的从表(城市).from("city")//学校是班级的从表 且设了结果集名为school 那么要获取学校字段 也只能由之前设立的学校结果集名.字段 来获取了.localField("school.cityId").foreignField("_id").as("city");//将几者关联关系放入管道中 作为条件进行查询Aggregation aggregation = Aggregation.newAggregation(lookupOne, lookupTwo, lookupThree);try {//注意,我这里还是以student为主表  那么查询结果第一视角(最外层)还是为studentAggregationResults<Map> aggregate = mongoTemplate.aggregate(aggregation, "student", Map.class);return JsonReturn.buildSuccess(aggregate.getMappedResults());} catch (Exception e) {e.printStackTrace();return JsonReturn.buildFailure("error");}}


那么文章到这里就告一段落了,随着后续的不断深入再继续更新吧

项目源码:Springboot整合Mongodb 连表查询

SpringBoot整合Mongodb(三) 使用MongoTemplate进行连表查询相关推荐

  1. SpringBoot整合MongoDB 及 基本使用

    目录 1.MongoDB基本介绍 2.MongoDB的特点 3.MongoDB的体系结构 4.MongoDB的数据类型 5.SpringBoot整合MongoDB ** 1.导入依赖 2.启动Mong ...

  2. Spring-Boot 整合MongoDB

    Spring-Boot 整合MongoDB 一.引入MongoDB依赖 <dependency><groupId>org.springframework.boot</gr ...

  3. SpringBoot 整合mongoDB实现文章存储

    本项目展示了 SpringBoot 整合mongoDB进行文章存储,并实现简单增删改查,关于docker安装MongoDB:Docker 安装 MongoDB_Michael-DYZ的博客-CSDN博 ...

  4. 直接裂开!京东二面被问SpringBoot整合MongoDB,我不会啊

    开始进入正题 一.技术介绍 SpringBoot整合MongoDB的实现步骤 一.技术介绍 1.MongoDB是什么? 二.使用步骤 1.MongoDB是什么? MongoDB(来自于英文单词&quo ...

  5. SpringBoot整合MongoDB数据库并实现基础CRUD

    MongoDB安装教程:MongoDB数据库安装以及将MongoDB设置为系统服务 MongoDB简介 MongoDB是一个基于分布式文件存储的数据库,由C++语言编写.旨为WEB应用提供可扩展的高性 ...

  6. 【ReactJs+springBoot项目——租房】第6章:MongoDB入门+SpringBoot整合MongoDB+搭建微聊系统+实现微聊功能

    MongoDB入门 MongoDB的java api的使用 SpringBoot整合MongoDB使用 搭建微聊系统 实现微聊功能 分布式WebSocket解决方案分析 1.MongoDB入门 1.1 ...

  7. springboot 整合 mongodb Criteria类 查询条件大全

    关于springboot整合mongodb,可查看博文 https://blog.csdn.net/qq_41712271/article/details/116062611 import cn.hu ...

  8. 运维高级学习(三):MySQL单表查询作业

    MySQL第三次作业 MySQL单表查询作业 素材如下: DROP TABLE IF EXISTS `course`; CREATE TABLE `course` ( `cs_id` int(11) ...

  9. core 实例化接口_实例讲解Springboot整合MongoDB进行CRUD操作的两种方式

    1 简介 Springboot是最简单的使用Spring的方式,而MongoDB是最流行的NoSQL数据库.两者在分布式.微服务架构中使用率极高,本文将用实例介绍如何在Springboot中整合Mon ...

最新文章

  1. 第十二篇:形式语言理论与有限状态自动机
  2. CADisplayLink 及定时器的使用
  3. 计算机原理 对口单招,对口单招计算机原理计算专题练习-20210622114415.pdf-原创力文档...
  4. C语言 递归实现辗转相除法 和 辗转相减法
  5. 杭十四计算机教室,杭十四中学生做了个图书馆智能机器人
  6. 演练:创建和使用静态库 (C++)
  7. python笔试编程题_Python——面试编程题
  8. 【GitLab】CentOS安装GitLab最佳实践
  9. 加油站都需要什么手续_公司变更需要什么手续
  10. paip.invalid conversion from FormWdg* to SOCKET {aka unsigned int}
  11. 《谈判是什么》笔记……
  12. 拨号保护,网络电话,保护隐私,匿名通话
  13. Builder模式创建实体类
  14. 灵棋排盘(七政四余)入门指导—排盘与框架
  15. 《opencv学习笔记》-- 感兴趣区域(ROI)、图像混合
  16. style是什么意思
  17. CocoStudio图片资源加密
  18. mysql数据库完整实例-“汽车维修”
  19. [FJOI2016]建筑师
  20. R语言生存分析数据分析可视化案例

热门文章

  1. Linux网络原理与编程——第十一节 网络基础及套接字
  2. MySQL字符串中文括号换行_MySQL的中文编码问题
  3. three.js教程创建消防场景示例二
  4. Win11家庭版系统加入域的问题解决
  5. 安卓Wifi设置DHCP以及静态IP
  6. 慢速,混合和快速衰减模式。为什么我们要把事情复杂化?
  7. 旅游市场复苏,旅行社小程序该怎么做?
  8. android 原生音量条
  9. 测试工程师长路漫漫,从测试0到测试1? 谁知道我经历了什么......
  10. 最终解决 No buffer space available maximum connections reached