当前位置:   article > 正文

Springboot整合MongoDB系列(五)---LookupOperation关联查询_lookupoperation.newlookup()

lookupoperation.newlookup()

继续MongoDB系列博客的第五篇,前面记录了使用MongoTemplate和MongoRepository进行查询的操作,今天记录一下mongo的关联查询,各位看到此博客的小伙伴,如有不对的地方请及时通过私信我或者评论此博客的方式指出,以免误人子弟。多谢!

目录

准备测试数据

学生与班级关联(学生为主表) - 多对一

不带条件的关联查询

查询条件来自主表

查询条件来自从表

多条件查询

模拟下实际情况

$unwind的效果

 学生与班级关联(班级为主表) - 一对多

学生、班级、学校关联(班级为主表) - 多对多

分页查询


准备测试数据

关联查询的测试,我们以学生、班级、学校为测试模型,进行一对多、多对一、多对多等情况下的关联查询。

  1. @Test
  2. public void addStudent(){
  3. List<Student> students = new ArrayList<>();
  4. Student student = Student.builder().id(1).username("zhangsan").classId(1).build();
  5. Student student1 = Student.builder().id(2).username("lisi").classId(2).build();
  6. Student student2 = Student.builder().id(3).username("wangwu").classId(2).build();
  7. students.add(student);
  8. students.add(student1);
  9. students.add(student2);
  10. mongotemplate.insertAll(students);
  11. }
  12. @Test
  13. public void addStudentClass(){
  14. List<StudentClass> studentClasses = new ArrayList<>();
  15. StudentClass studentClass = new StudentClass(1,"class one",1);
  16. StudentClass studentClass1 = new StudentClass(2,"class two",2);
  17. studentClasses.add(studentClass);
  18. studentClasses.add(studentClass1);
  19. mongotemplate.insertAll(studentClasses);
  20. }
  21. @Test
  22. public void addSchool(){
  23. List<School> schoolList = new ArrayList<>();
  24. School school = new School(1,"一中");
  25. School school1 = new School(2,"二中");
  26. schoolList.add(school);
  27. schoolList.add(school1);
  28. mongotemplate.insertAll(schoolList);
  29. }

学生与班级关联(学生为主表) - 多对一

我们使用 ClassStudentsDto 为返回实体:

  1. @Data
  2. public class ClassStudentsDto {
  3. private Integer id;
  4. private String username;
  5. private Integer classId;
  6. private List<StudentClass> classStudents;
  7. }

先看下LookupOperation的使用方法:

  1. LookupOperation lookupOperation = LookupOperation.newLookup()
  2. .from("studentClass")//关联从表名
  3. .localField("classId")//主表中的关联字段
  4. .foreignField("_id")//从表关联的字段
  5. .as("classStudents");//查询结果名

但是源码中不推荐使用这种方式,建议使用静态工厂方法Aggregation.lookup(String, String, String, String)而不是直接创建此类的实例,以下我们都会使用静态工厂方法来创建LookupOperation。

不带条件的关联查询

先看一下不带条件的关联查询,我们分别使用Map和对象的方式接收放回结果。

  1. @Test
  2. public void test(){
  3. LookupOperation lookupOperation = LookupOperation.newLookup()
  4. .from("studentClass")//关联从表名
  5. .localField("classId")//主表中的关联字段
  6. .foreignField("_id")//从表关联的字段
  7. .as("classStudents");//查询结果名
  8. // 源码中建议使用静态工厂方法Aggregation.lookup(String, String, String, String)而不是直接创建此类的实例
  9. LookupOperation lookup = Aggregation.lookup("studentClass", "classId", "_id",
  10. "classStudents");
  11. Aggregation aggregation = Aggregation.newAggregation(lookup);
  12. // 使用Map接收结果
  13. AggregationResults<Map> results = mongotemplate.aggregate(aggregation, "student",
  14. Map.class);
  15. System.out.println(results.getMappedResults());
  16. // 使用对象接收结果
  17. AggregationResults<ClassStudentsDto> results1 = mongotemplate.aggregate(aggregation,
  18. "student", ClassStudentsDto.class);
  19. System.out.println(results1.getMappedResults());
  20. }

查询条件来自主表

  1. @Test
  2. public void test1(){
  3. LookupOperation lookup = Aggregation.lookup("studentClass", "classId", "_id",
  4. "classStudents");
  5. // 追加查询条件 -- 查询条件来自主表
  6. Criteria criteria = Criteria.where("classId").is(2);
  7. // 将筛选条件放入管道
  8. MatchOperation match = Aggregation.match(criteria);
  9. Aggregation aggregation1 = Aggregation.newAggregation(lookup, match);
  10. AggregationResults<ClassStudentsDto> results2 = mongotemplate.aggregate(aggregation1,
  11. "student", ClassStudentsDto.class);
  12. System.out.println(results2.getMappedResults());
  13. }

查询条件来自从表

查询条件来自从表时,不能直接使用从表的属性进行查询,而是要通过LookupOperation的查询结果名(也就是Aggregation.lookup的第四个参数)来获取,即:查询结果名.属性。

  1. @Test
  2. public void test2(){
  3. LookupOperation lookup = Aggregation.lookup("studentClass", "classId", "_id",
  4. "classStudents");
  5. // 追加查询条件 -- 查询条件来自从表 classStudents为上面as 查询结果名
  6. Criteria criteria1 = Criteria.where("classStudents._id").is(2);
  7. MatchOperation match1 = Aggregation.match(criteria1);
  8. Aggregation aggregation2 = Aggregation.newAggregation(lookup, match1);
  9. AggregationResults<ClassStudentsDto> results3 = mongotemplate.aggregate(aggregation2,
  10. "student", ClassStudentsDto.class);
  11. System.out.println(results3.getMappedResults());
  12. }

多条件查询

  1. /**
  2. * 多条件追加:
  3. * 1.通过使用 andOperator(Criteria... criteria) 追加多个条件
  4. * 2.通过and(String key) 追加多个条件
  5. */
  6. @Test
  7. public void test3(){
  8. LookupOperation lookup = Aggregation.lookup("studentClass", "classId", "_id",
  9. "classStudents");
  10. // 多个条件
  11. Criteria criteria2 = Criteria.where("classId").is(2);
  12. Criteria criteria3 = Criteria.where("username").is("lisi");
  13. Criteria criterias = new Criteria().andOperator(criteria2,criteria3);
  14. MatchOperation match2 = Aggregation.match(criterias);
  15. Aggregation aggregation3 = Aggregation.newAggregation(lookup, match2);
  16. AggregationResults<ClassStudentsDto> results4 = mongotemplate.aggregate(aggregation3,
  17. "student", ClassStudentsDto.class);
  18. System.out.println(results4.getMappedResults());
  19. Criteria criteria = new Criteria();
  20. criteria.and("classId").is(2).and("username").is("lisi");
  21. MatchOperation match = Aggregation.match(criteria);
  22. Aggregation aggregation = Aggregation.newAggregation(lookup, match);
  23. AggregationResults<ClassStudentsDto> results = mongotemplate.aggregate(aggregation,
  24. "student", ClassStudentsDto.class);
  25. System.out.println(results.getMappedResults());
  26. }

模拟下实际情况

  1. /**
  2. * 通常查询条件要判断一下是否为空 然后再进行条件设置
  3. */
  4. @Test
  5. public void test4(){
  6. LookupOperation lookup = Aggregation.lookup("studentClass", "classId", "_id",
  7. "classStudents");
  8. Integer classId = 2;
  9. String username = "lisi";
  10. Criteria criteria = new Criteria();
  11. if(classId != null){
  12. criteria.and("classId").is(classId);
  13. }
  14. if(StringUtils.isNotBlank(username)){
  15. criteria.and("username").is(username);
  16. }
  17. MatchOperation match = Aggregation.match(criteria);
  18. Aggregation aggregation = Aggregation.newAggregation(lookup, match);
  19. AggregationResults<ClassStudentsDto> results = mongotemplate.aggregate(aggregation,
  20. "student", ClassStudentsDto.class);
  21. System.out.println(results.getMappedResults());
  22. }

$unwind的效果

  1. /**
  2. * $unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
  3. * 啥效果啥作用呢?
  4. * 看两张截图
  5. * 没使用unwind前会多嵌套了一层 使用后好比是把里面一层拍扁了 少了一层利于取值
  6. * 其实在使用对象接收查询结果后就不必使用unwind了 对象取值还是很方便的
  7. * 而且使用对象接收后 使用unwind会报类型转换异常的错误
  8. */
  9. @Test
  10. public void test5(){
  11. LookupOperation lookup = Aggregation.lookup("studentClass", "classId", "_id",
  12. "classStudents");
  13. Criteria criteria = Criteria.where("classId").is(2);
  14. MatchOperation match = Aggregation.match(criteria);
  15. Aggregation aggregation = Aggregation.newAggregation(lookup, match,Aggregation.unwind("classStudents"));
  16. AggregationResults<Map> results = mongotemplate.aggregate(aggregation,
  17. "student", Map.class);
  18. System.out.println(results);
  19. }

 学生与班级关联(班级为主表) - 一对多

我们使用 StudentDto为返回实体:

  1. @Data
  2. public class StudentDto {
  3. private Integer id;
  4. private String className;
  5. private List<Student> studentList;
  6. }
  1. @Test
  2. public void test6(){
  3. LookupOperation lookup = Aggregation.lookup("student", "_id", "classId",
  4. "studentList");
  5. Aggregation aggregation = Aggregation.newAggregation(lookup);
  6. AggregationResults<StudentDto> results = mongotemplate.aggregate(aggregation, "studentClass"
  7. , StudentDto.class);
  8. System.out.println(results.getMappedResults());
  9. }

学生、班级、学校关联(班级为主表) - 多对多

  1. /**
  2. * 多表关联查询时 可能从表会是下一次查询的主表 比如学员关联班机、班级关联学校,班级关联学校时 班级表就成了主表
  3. * 那么在班级表和学校表关联时 localField就不能直接写schoolId 而是通过上一步的结果集来取值
  4. * 如:classStudents.schoolId
  5. * 同样我们想只返回指定字段时,也需要通过上一步的结果集来取想要的属性,
  6. * 如:classStudents.className schoolClasses.schoolName
  7. */
  8. @Test
  9. public void test7(){
  10. // 学员表关联班级表
  11. LookupOperation lookup = Aggregation.lookup("studentClass", "classId", "_id",
  12. "classStudents");
  13. // 班级表关联学校表
  14. LookupOperation lookup1 = Aggregation.lookup("school", "classStudents.schoolId", "_id",
  15. "schoolClasses");
  16. Aggregation aggregation = Aggregation.newAggregation(lookup, lookup1);
  17. AggregationResults<Map> results = mongotemplate.aggregate(aggregation, "student",
  18. Map.class);
  19. System.out.println(results);
  20. AggregationResults<StudentClassSchoolDto> results1 = mongotemplate.aggregate(aggregation,
  21. "student", StudentClassSchoolDto.class);
  22. // [StudentClassSchoolDto(id=1, username=zhangsan, classStudents=StudentClass(id=1, className=class one, schoolId=1), schoolClasses=School(id=1, schoolName=一中)), StudentClassSchoolDto(id=2, username=lisi, classStudents=StudentClass(id=2, className=class two, schoolId=2), schoolClasses=School(id=2, schoolName=二中)), StudentClassSchoolDto(id=3, username=wangwu, classStudents=StudentClass(id=2, className=class two, schoolId=2), schoolClasses=School(id=2, schoolName=二中))]
  23. System.out.println(results1.getMappedResults());
  24. // 只返回指定字段
  25. ProjectionOperation project = Aggregation.project("id","username","classStudents.className","schoolClasses.schoolName");
  26. Aggregation aggregation1 = Aggregation.newAggregation(lookup, lookup1, project);
  27. AggregationResults<StudentClassSchoolDto> results2 = mongotemplate.aggregate(aggregation1,
  28. "student", StudentClassSchoolDto.class);
  29. // [StudentClassSchoolDto(id=1, username=zhangsan, className=class one, schoolName=一中), StudentClassSchoolDto(id=2, username=lisi, className=class two, schoolName=二中), StudentClassSchoolDto(id=3, username=wangwu, className=class two, schoolName=二中)]
  30. System.out.println(results2.getMappedResults());
  31. }

分页查询

  1. @Test
  2. public void test8(){
  3. LookupOperation lookup = Aggregation.lookup("studentClass", "classId", "_id",
  4. "classStudents");
  5. int pageNum = 0;
  6. int pageSize = 2;
  7. Pageable pageable = PageRequest.of(pageNum, pageSize);
  8. SkipOperation skip = Aggregation.skip((long) pageable.getPageNumber() > 0 ? (pageable.getPageNumber() - 1) * pageable.getPageSize() : 0L);
  9. LimitOperation limit = Aggregation.limit(pageable.getPageSize());
  10. Aggregation aggregation = Aggregation.newAggregation(lookup, skip, limit);
  11. // 当前页数据
  12. AggregationResults<ClassStudentsDto> results = mongotemplate.aggregate(aggregation,
  13. "student", ClassStudentsDto.class);
  14. // 总条数
  15. AggregationResults<ClassStudentsDto> results1 =
  16. mongotemplate.aggregate(Aggregation.newAggregation(lookup), "student",
  17. ClassStudentsDto.class);
  18. long total = results1.getMappedResults().size();
  19. Page<ClassStudentsDto> tPage = PageableExecutionUtils.getPage(results.getMappedResults(),
  20. pageable, () -> total);
  21. System.out.println("---getTotalElements---" + tPage.getTotalElements());// 总记录数
  22. System.out.println("---getTotalPages---" + tPage.getTotalPages());// 总页数
  23. System.out.println("---getNumber---" + tPage.getNumber());// 当前页
  24. System.out.println("---getSize---" + tPage.getSize());// 每页大小
  25. System.out.println("---getContent---" + tPage.getContent()); // 数据
  26. System.out.println("---getNumberOfElements---" + tPage.getNumberOfElements());// 当前页的元素数
  27. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/56034
推荐阅读
相关标签
  

闽ICP备14008679号