1.分页查询
skip+limit形式
mongo中可通过skip+limit来实现文档批量查询的分页逻辑实现,具体javaAPI代码操作如下
@Test
void testSelect() {
//1.保存测试数据
for (int i = 1; i <= 10; i++) {
Student student = new Student();
student.setId(i);
student.setName(i + "ftc");
student.setAge(i);
mongoTemplate.insert(student);
}
//2.验证数据存入
long count = mongoTemplate.count(new Query(), Student.class);
Assert.isTrue(10 == count);
//3.限制条数查询
Query query = new Query().limit(2);
List<Student> students = mongoTemplate.find(query, Student.class);
Assert.isTrue(2 == students.size());
//4.跳过指定条数查询
query = new Query().skip(5);
Student student = mongoTemplate.findOne(query, Student.class);
Assert.isTrue(6 == student.getAge());
//5.分页查询
int pageNum = 4;
int pageSize = 2;
query = new Query().skip((pageNum - 1) * pageSize).limit(pageSize);
students = mongoTemplate.find(query, Student.class);
Assert.isTrue(7 == students.get(0).getId());
Assert.isTrue(8 == students.get(1).getId());
}
PageRequest形式
PageRequest类路径:import org.springframework.data.domain.PageRequest;
具体javaAPI如下:
@Test
void testSelect() {
//1.保存测试数据
for (int i = 1; i <= 10; i++) {
Student student = new Student();
student.setId(i);
student.setName(i + "ftc");
student.setAge(i);
mongoTemplate.insert(student);
}
//2.验证数据存入
long count = mongoTemplate.count(new Query(), Student.class);
Assert.isTrue(10 == count);
//3.分页查询
int pageNum = 4;
int pageSize = 2;
PageRequest pageRequest = PageRequest.of(pageNum - 1, pageSize);
Query query = new Query().with(pageRequest);
List<Student> students = mongoTemplate.find(query, Student.class);
Assert.isTrue(7 == students.get(0).getId());
Assert.isTrue(8 == students.get(1).getId());
}
2.排序
springboot中通过Sort类来指定排序顺序,类路径:import org.springframework.data.domain.Sort;
具体代码如下
@Test
void testSelect() {
//1.保存测试数据
for (int i = 1; i <= 10; i++) {
Student student = new Student();
student.setId(i);
student.setName(i + "ftc");
student.setAge(i);
mongoTemplate.insert(student);
}
//2.验证数据存入
long count = mongoTemplate.count(new Query(), Student.class);
Assert.isTrue(10 == count);
//3.单一排序查询
Sort sort = Sort.by(Sort.Direction.DESC, "id");
List<Student> students = mongoTemplate.find(new Query().with(sort), Student.class);
Assert.isTrue(students.get(0).getAge() == 10);
Assert.isTrue(students.get(9).getAge() == 1);
//4.组合排序查询
sort = Sort.by(Sort.Direction.ASC, "id").and(Sort.by(Sort.Direction.ASC, "age"));
students = mongoTemplate.find(new Query().with(sort), Student.class);
Assert.isTrue(students.get(0).getAge() == 1);
Assert.isTrue(students.get(9).getAge() == 10);
}
3.聚合
springboot中每个聚合管道符都封装了不同的Operation,最终将这些operation整和到一个Aggregation,
最终在查询时,使用Aggregation即可查询
具体javaAPI如下
@Test
void testSelect() {
//1.保存测试数据
for (int i = 1; i <= 10; i++) {
Student student = new Student();
student.setId(i);
student.setName(i + "ftc");
student.setAge(i);
student.setSex(i % 2 == 0 ? 1 : 0);
mongoTemplate.insert(student);
}
//2.验证数据存入
long count = mongoTemplate.count(new Query(), Student.class);
Assert.isTrue(10 == count);
//3.聚合操作,获取年龄总和
GroupOperation groupOperation = Aggregation.group().sum("age").as("ageSum");
TypedAggregation<Student> typedAggregation = Aggregation.newAggregation(Student.class, groupOperation);
AggregationResults<JSONObject> aggregationResult = mongoTemplate.aggregate(typedAggregation, JSONObject.class);
JSONObject result = aggregationResult.getUniqueMappedResult();
Assert.isTrue(55 == result.getInt("ageSum"));
//4.获取不同性别的人数
groupOperation = Aggregation.group("sex").count().as("agePeopleSum");
typedAggregation = Aggregation.newAggregation(Student.class, groupOperation);
aggregationResult = mongoTemplate.aggregate(typedAggregation, JSONObject.class);
List<JSONObject> results = aggregationResult.getMappedResults();
Assert.isTrue(2 == results.size());
Assert.isTrue(5 == results.get(0).getInt("agePeopleSum"));
Assert.isTrue(5 == results.get(1).getInt("agePeopleSum"));
//5.获取年龄平均值
groupOperation = Aggregation.group().avg("age").as("aveAge");
typedAggregation = Aggregation.newAggregation(Student.class, groupOperation);
aggregationResult = mongoTemplate.aggregate(typedAggregation, JSONObject.class);
result = aggregationResult.getUniqueMappedResult();
Assert.isTrue(5.5 == result.getDouble("aveAge"));
//6.计算年龄最大值
groupOperation = Aggregation.group().max("age").as("maxAge");
typedAggregation = Aggregation.newAggregation(Student.class, groupOperation);
aggregationResult = mongoTemplate.aggregate(typedAggregation, JSONObject.class);
result = aggregationResult.getUniqueMappedResult();
Assert.isTrue(10 == result.getInt("maxAge"));
//7.计算年龄大于3的总人数
MatchOperation matchOperation = Aggregation.match(Criteria.where("age").gt(3));
groupOperation = Aggregation.group().count().as("peopleSum");
typedAggregation = Aggregation.newAggregation(Student.class, matchOperation, groupOperation);
aggregationResult = mongoTemplate.aggregate(typedAggregation, JSONObject.class);
result = aggregationResult.getUniqueMappedResult();
Assert.isTrue(7 == result.getInt("peopleSum"));
}
4.联合查询
mongo中虽然提供了lookup进行多表联查,但是个人还是觉得,mongo中能用嵌入式数据结构存储,还是优先使用嵌入式数据结构存储
嵌入式数据模型
- 定义学生,成绩实体类。学生属性中嵌套了成绩集合 ```java import lombok.Data; import org.springframework.data.mongodb.core.mapping.Document;
import java.util.List;
/**
- @author 冯铁城 [17615007230@163.com]
- @date 2022-07-20 19:12:01
- @describe: MongoDB实体类
“@Document(collection = “student”)” 用于指定对应哪个集合 */ @Data @Document(collection = “student”) public class Student {
private long id;
private String name;
private int age;
/**
性别 1-男 0-女 */ private int sex;
private List
grades; }
/**
- @author 冯铁城 [17615007230@163.com]
- @date 2022-07-25 18:26:51
@describe: */ @Data public class Grade {
private String name;
private Double score; } ```
直接查询即可获取到嵌套的成绩集合
@Test
void testSelect() {
//1.定义成绩集合
List<Grade> grades = CollUtil.newArrayList();
Grade grade = new Grade();
grade.setName("语文");
grade.setScore(77.7);
grades.add(grade);
grade = new Grade();
grade.setName("数学");
grade.setScore(66.8);
grades.add(grade);
grade = new Grade();
grade.setName("英语");
grade.setScore(99.3);
grades.add(grade);
//2.定义学生
Student student = new Student();
student.setAge(18);
student.setSex(1);
student.setName("冯铁城");
student.setGrades(grades);
//3.存储
mongoTemplate.insert(student);
Student result = mongoTemplate.findOne(new Query(), Student.class);
Assert.isTrue(result.getAge() == student.getAge());
Assert.isTrue(result.getName().equals(student.getName()));
Assert.isTrue(result.getSex() == student.getSex());
Assert.isTrue(JSONUtil.toJsonStr(result.getGrades()).equals(JSONUtil.toJsonStr(student.getGrades())));
}
引用式数据模型
使用unwind管道符
使用unwind会将指定的聚合数组字段拆分为多条数据
定义成绩类,对应成绩文档 ```java import lombok.Data; import org.springframework.data.mongodb.core.mapping.Document;
/**
- @author 冯铁城 [17615007230@163.com]
- @date 2022-07-25 18:26:51
@describe: */ @Data @Document(collection = “grade”) public class Grade {
private String id;
private String studentId;
private String name;
private Double score; } ```
- 定义学生类,对应学生文档 ```java import lombok.Data; import org.springframework.data.mongodb.core.mapping.Document;
/**
- @author 冯铁城 [17615007230@163.com]
- @date 2022-07-20 19:12:01
- @describe: MongoDB实体类
“@Document(collection = “student”)” 用于指定对应哪个集合 */ @Data @Document(collection = “student”) public class Student {
private String id;
private String name;
private int age;
/**
性别 1-男 0-女 */ private int sex;
private Grade grade; } ```
使用lookup进行查询
@Test
void testSelect() {
//1.定义学生
Student student = new Student();
student.setAge(18);
student.setSex(1);
student.setName("冯铁城");
student = mongoTemplate.insert(student);
//2.定义成绩
List<Grade> grades = CollUtil.newArrayList();
Grade grade = new Grade();
grade.setName("语文");
grade.setScore(77.7);
grade.setStudentId(student.getId());
grades.add(grade);
grade = new Grade();
grade.setName("数学");
grade.setScore(66.8);
grade.setStudentId(student.getId());
grades.add(grade);
grade = new Grade();
grade.setName("英语");
grade.setScore(99.3);
grade.setStudentId(student.getId());
grades.add(grade);
mongoTemplate.insert(grades, Grade.class);
//3.定义lookup、unwind管道符
LookupOperation lookupOperation = Aggregation.lookup("grade", "id", "student_id", "grade");
UnwindOperation unwindOperation = Aggregation.unwind("grade");
TypedAggregation<Student> typedAggregation = Aggregation.newAggregation(Student.class, lookupOperation, unwindOperation);
//4.查询
AggregationResults<Student> aggregate = mongoTemplate.aggregate(typedAggregation, Student.class);
List<Student> students = aggregate.getMappedResults();
Console.log(JSONUtil.toJsonPrettyStr(students));
}
验证

不使用unwind管道符
- 定义成绩类,对应成绩文档(与使用unwind一致,不做过多累述)
- 定义学生类,对应学生文档 ```java import lombok.Data; import org.springframework.data.mongodb.core.mapping.Document;
import java.util.List;
/**
- @author 冯铁城 [17615007230@163.com]
- @date 2022-07-20 19:12:01
- @describe: MongoDB实体类
“@Document(collection = “student”)” 用于指定对应哪个集合 */ @Data @Document(collection = “student”) public class Student {
private String id;
private String name;
private int age;
/**
性别 1-男 0-女 */ private int sex;
private List
grades; } ```
使用lookup进行查询
@Test
void testSelect() {
//1.定义学生
Student student = new Student();
student.setAge(18);
student.setSex(1);
student.setName("冯铁城");
student = mongoTemplate.insert(student);
//2.定义成绩
List<Grade> grades = CollUtil.newArrayList();
Grade grade = new Grade();
grade.setName("语文");
grade.setScore(77.7);
grade.setStudentId(student.getId());
grades.add(grade);
grade = new Grade();
grade.setName("数学");
grade.setScore(66.8);
grade.setStudentId(student.getId());
grades.add(grade);
grade = new Grade();
grade.setName("英语");
grade.setScore(99.3);
grade.setStudentId(student.getId());
grades.add(grade);
mongoTemplate.insert(grades, Grade.class);
//3.定义lookup、unwind管道符
LookupOperation lookupOperation = Aggregation.lookup("grade", "id", "student_id", "grades");
TypedAggregation<Student> typedAggregation = Aggregation.newAggregation(Student.class, lookupOperation);
//4.查询
AggregationResults<Student> aggregate = mongoTemplate.aggregate(typedAggregation, Student.class);
Student result = aggregate.getUniqueMappedResult();
Console.log(JSONUtil.toJsonPrettyStr(result));
}
验证
控制台输入如图,多表联查成功