SpringBoot整合MongoDB JPA,测试MongoRepository与MongoTemplate用法,简单增删改查+高级聚合

点击查看测试项目 springboot-mongo

总体代码截图预览

在这里插入图片描述
在这里插入图片描述

引入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<dependencies>
<!--mongo操作mongo-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>2.1.8.RELEASE</version>
</dependency>
<!--lombok简化实体类-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
<!--test测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.1.8.RELEASE</version>
</dependency>
</dependencies>

配置MongoDB信息

1
2
3
4
5
6
7
8
#mongo01是数据库
spring.data.mongodb.uri=mongodb://192.168.1.3:27018/mongo01

#账号密码配置
#spring.data.mongodb.uri=mongodb://user:pwd@ip:port/db

#多节点配置
#spring.data.mongodb.uri=mongodb://user:pwd@ip1:port1,ip2:port2/db

添加SpringBoot主配置类

1
2
3
4
5
6
7
8
9
10
11
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringbootMongoApplication
{
public static void main(String[] args)
{
SpringApplication.run(SpringbootMongoApplication.class);
}
}

创建实体类

Grade

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

import java.util.List;

@Document(collection = "grade")//对应表名
@Data//setter getter toString
@NoArgsConstructor//无参构造
@AllArgsConstructor//全参构造
public class Grade
{
@Id//主键
private String id;
private Integer grade_id;
private String grade_name;
private List<Student> student_list;
}

Student

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;

@Document(collection = "student")//对应表名
@Data//setter getter toString
@NoArgsConstructor//无参构造
@AllArgsConstructor//全参构造
public class Student
{
@Id//主键
private String id;
@Field("stu_name")//对应列名
private String stu_name;
private Integer age;
private Integer grade_id;
private Grade grade;
}

MongoRepository

这个方便对实体类映射进行简单的增删改查以及分页
查询支持@Query注解,增删改不支持注解,只有自带的方法
不支持多表(Lookup)+聚合(Aggregation)+分布式计算(MapReduce)
这里我只演示查询就行了,其他的没什么好说的…
主要讲MongoTemplate

StudentRepository

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import panfeng.pojo.Student;

import java.util.List;

public interface StudentRepository extends MongoRepository<Student, String>
{
@Query("{'stu_name':?0}}")
List<Student> findStudentsByStu_name(String stu_name);

@Query("{'stu_name':{$regex:'?0'}}")
List<Student> findStudentsByStu_nameBetween(String stu_name);

@Query("{'stu_name':{$regex:'^?0'}}")
List<Student> findStudentsByStu_nameStartingWith(String stu_name);

@Query("{$and:[{'stu_name':?0},{'age':?1}]}")
List<Student> findStudentsByStu_nameaAndAge(String stu_name,Integer age);
}

MongoRepositoryTest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.test.context.junit4.SpringRunner;
import panfeng.repository.StudentRepository;

@RunWith(SpringRunner.class)
@SpringBootTest
public class MongoRepositoryTest
{
@Autowired
private StudentRepository studentRepository;

/**
* 总体来说不太方便,没有 MongoTemplate 方便
*/

/*测试数据 表名 student

{"stu_name":"大牛哥哥","age":15,"grade_id":1}
{"stu_name":"二蛋","age":11,"grade_id":2}
{"stu_name":"三驴","age":18,"grade_id":3}
{"stu_name":"四毛","age":18,"grade_id":1}
{"stu_name":"五虎","age":20,"grade_id":2}
{"stu_name":"六豹子","age":13,"grade_id":3}
{"stu_name":"六豹子","age":17,"grade_id":3}
{"stu_name":"豹","age":11,"grade_id":3}

*/

@Test
public void select()
{
//查询所有 *
// studentRepository.findAll().forEach(System.out::println);
//查询所有并按照年龄排序
// Sort sort = new Sort(Sort.Direction.ASC, "age");
// studentRepository.findAll(sort).forEach(System.out::println);
//分页 每页2条 查询第二页
// PageRequest pageRequest = new PageRequest(1, 2);//page 0第一页 1第二页
// studentRepository.findAll(pageRequest).forEach(System.out::println);
//根据名称查询 stu_name='六豹子'
// studentRepository.findStudentsByStu_name("六豹子").forEach(System.out::println);
//模糊查询 stu_name like '%豹%'
// studentRepository.findStudentsByStu_nameBetween("豹").forEach(System.out::println);
//模糊查询以什么开头 stu_name like '豹%'
// studentRepository.findStudentsByStu_nameStartingWith("豹").forEach(System.out::println);
//查询 stu_name=六豹子 and age=13
// studentRepository.findStudentsByStu_nameaAndAge("六豹子",13).forEach(System.out::println);
}
}

MongoTemplate

注意

每个方法最后一项配合Document的使用

方法预览

先把大致内容写出来,再逐个写方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.MapReduceCommand;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import com.sun.beans.decoder.ValueObject;
import org.bson.BsonDocument;
import org.bson.Document;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions;
import org.springframework.data.mongodb.core.mapreduce.MapReduceResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.test.context.junit4.SpringRunner;
import panfeng.pojo.Grade;
import panfeng.pojo.Student;
import panfeng.repository.StudentRepository;

import java.util.Iterator;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class MongoTemplateTest
{
@Autowired
private MongoTemplate mongoTemplate;

@Test
public void insert() throws Exception
{
}

@Test
public void delete() throws Exception
{
}

@Test
public void update() throws Exception
{
}

@Test
public void select() throws Exception
{
}

@Test
public void aggregation() throws Exception
{
}

@Test
public void mapReduce() throws Exception
{
}
}

insert()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    @Test
public void insert() throws Exception
{
//插入学生数据
// mongoTemplate.save(new Student(null, "大牛哥哥", 15, 1, null));
// mongoTemplate.save(new Student(null, "二蛋", 11, 2, null));
// mongoTemplate.save(new Student(null, "三驴", 18, 3, null));
// mongoTemplate.save(new Student(null, "四毛", 18, 1, null));
// mongoTemplate.save(new Student(null, "五虎", 20, 2, null));
// mongoTemplate.save(new Student(null, "六豹子", 13, 3, null));
// mongoTemplate.save(new Student(null, "六豹子", 17, 3, null));
// mongoTemplate.save(new Student(null, "豹", 11, 3, null));
//插入年级数据
// mongoTemplate.save(new Grade(null,1,"一年级"));
// mongoTemplate.save(new Grade(null,2,"二年级"));
// mongoTemplate.save(new Grade(null,3,"三年级"));
//插入学生 -> Document模式
// Document document=new Document()
// .append("stu_name","陶攀峰")
// .append("age",26)
// .append("grade_id",4);
// mongoTemplate.save(document,"student");
}

delete()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    @Test
public void delete() throws Exception
{
//删除所有grade_id=3
// Query query = Query.query(Criteria.where("grade_id").is(3));
// DeleteResult deleteResult = mongoTemplate.remove(query, Student.class);
// System.out.println(deleteResult.getDeletedCount());//删除的数量
//删除全部
// DeleteResult deleteResult = mongoTemplate.remove(new Query(), Student.class);
// System.out.println(deleteResult.getDeletedCount());//删除的数量
//删除所有 age=4 -> 表 student
// Query query = Query.query(Criteria.where("age").is(4));
// DeleteResult deleteResult = mongoTemplate.remove(query, "student");
// System.out.println(deleteResult.getDeletedCount());//删除的数量
}

update()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    @Test
public void update() throws Exception
{
//修改stu_name="三驴" and age!=18的第一条记录 -> stu_name="三驴弟弟",age=18
// Query query=Query.query(Criteria.where("stu_name").is("三驴").and("age").ne(18));
// Update update = new Update().set("stu_name", "三驴弟弟").set("age", 19);
// UpdateResult updateResult = mongoTemplate.updateFirst(query, update, Student.class);
// System.out.println(updateResult.getModifiedCount());//修改多少条
//修改所有的address="9527" 如果不存在就插入字段,如果存在则修改,也会改变字段类型
// Update update = new Update().set("address", "9527");
// UpdateResult updateResult = mongoTemplate.updateMulti(new Query(), update, Student.class);
// System.out.println(updateResult.getModifiedCount());//修改多少条
//修改表 student 所有的stu_name="陶攀峰" -> stu_name="陶攀峰1",age=27
// Query query = Query.query(Criteria.where("stu_name").is("陶攀峰"));
// Update update = new Update().set("stu_name", "陶攀峰1").set("age", 27);
// UpdateResult updateResult = mongoTemplate.updateMulti(query, update, "student");
// System.out.println(updateResult.getModifiedCount());//修改多少条
}

select()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
    @Test
public void select() throws Exception
{
//查询对应Document
// mongoTemplate.findAll(Document.class, "student").forEach(System.out::println);
//查询所有的数据 -> 循环打印数据
// mongoTemplate.findAll(Student.class).forEach(System.out::println);
// System.out.println("共计" + mongoTemplate.findAll(Student.class).size() + "条...");
//查询stu_name="三驴"
// Query query=Query.query(Criteria.where("stu_name").is("三驴"));
// mongoTemplate.find(query, Student.class).forEach(System.out::println);
//查询age>18
// Query query=Query.query(Criteria.where("age").gt(18));
// mongoTemplate.find(query,Student.class).forEach(System.out::println);
//查询stu_name="三驴" and age>16
// Query query=Query.query(Criteria.where("stu_name").is("三驴").and("age").gt(16));
// mongoTemplate.find(query,Student.class).forEach(System.out::println);
//查询stu_name like '%牛%'
// Query query = Query.query(Criteria.where("stu_name").regex("牛"));
// mongoTemplate.find(query, Student.class).forEach(System.out::println);
//查询stu_name like '五%'
// Query query = Query.query(Criteria.where("stu_name").regex("^五"));
// mongoTemplate.find(query, Student.class).forEach(System.out::println);
//查询age>15 并且按照age 降序
// Query query = Query.query(Criteria.where("age").gt(15)).with(new Sort(Sort.Direction.DESC, "age"));
// mongoTemplate.find(query,Student.class).forEach(System.out::println);
//查询排序并分页
// Query query=new Query();
// query.with(new Sort(Sort.Direction.ASC,"age"));//按照age升序
// query.with(new PageRequest(1,3));//page 0第一页 1第二页 -> 3每页三条记录
// mongoTemplate.find(query,Student.class).forEach(System.out::println);
//查询去除前2条,再取前三条 -> 取第3 4 5 条记录
// Query query=new Query();
// query.skip(2);
// query.limit(3);
// mongoTemplate.find(query,Student.class).forEach(System.out::println);
//查询去除前2条,再取前三条 -> 取第3 4 5 条记录 -> 返回 Document
// Query query=new Query().skip(2).limit(3);
// mongoTemplate.find(query,Document.class,"student").forEach(System.out::println);
}

aggregation()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
    @Test
public void aggregation() throws Exception
{
//查询所有学生,并关联到对应的年级 -> 从表.主表字段.从表字段.添加主表字段名称
// LookupOperation lookupOperation = Aggregation.lookup("grade", "grade_id", "grade_id", "grade");
// Aggregation aggregation = Aggregation.newAggregation(lookupOperation);
// //如果collection=主表名称
// //Student.class是对应主表的类,输出类型
// List<Student> student_list = mongoTemplate.aggregate(aggregation, "student", Student.class).getMappedResults();
// student_list.forEach(System.out::println);
//查询所有年级,并关联到对应的学生 -> 从表.主表字段.从表字段.添加主表字段名称
// LookupOperation lookupOperation = Aggregation.lookup("student", "grade_id", "grade_id", "student_list");
// Aggregation aggregation = Aggregation.newAggregation(lookupOperation);
// //如果collection=主表名称
// //Grade.class是对应主表的类,输出类型
// List<Grade> grade_list = mongoTemplate.aggregate(aggregation, "grade", Grade.class).getMappedResults();
// grade_list.forEach(System.out::println);
//查询所有学生,并关联到对应的年级,输出Document -> 从表.主表字段.从表字段.添加主表字段名称
// LookupOperation lookupOperation = Aggregation.lookup("grade", "grade_id", "grade_id", "grade");
// Aggregation aggregation = Aggregation.newAggregation(lookupOperation);
// List<Document> document_list = mongoTemplate.aggregate(aggregation, "student", Document.class).getMappedResults();
// document_list.forEach(System.out::println);
// document_list.forEach(document ->
// {
// System.out.println(document.get("age"));//输出age字段
// });
//管道过滤
// //1,查询age>11
// MatchOperation matchOperation = Aggregation.match(Criteria.where("age").gt(11));
// //2,使student与grade匹配,将匹配到的grade添加到grade字段 -> 从表.主表字段.从表字段.添加主表字段名称
// LookupOperation lookupOperation = Aggregation.lookup("grade", "grade_id", "grade_id", "grade");
// //3,按照age升序
// SortOperation sortOperation = Aggregation.sort(Sort.Direction.ASC, "age");
// //4,去除前2个值
// SkipOperation skipOperation = Aggregation.skip(2);
// //5,查询前3个值
// LimitOperation limitOperation = Aggregation.limit(3);
// //6,按照age分组,取个别名age_group记录按age分组的数量
// GroupOperation groupOperation = Aggregation.group("age").count().as("age_group");
// //7,获取总记录数,取个别名count
// CountOperation countOperation = Aggregation.count().as("count");
// //Aggregation aggregation = Aggregation.newAggregation(groupOperation);
// //Aggregation aggregation = Aggregation.newAggregation(countOperation);
// Aggregation aggregation = Aggregation.newAggregation(matchOperation, lookupOperation, sortOperation, skipOperation, limitOperation);
// //如果collection=主表名称
// //Document.class是对应输出类型
// List<Document> document_list = mongoTemplate.aggregate(aggregation, "student", Document.class).getMappedResults();
// document_list.forEach(System.out::println);
}

mapReduce()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
    @Test
public void mapReduce() throws Exception
{
/*测试数据 表名 a
{_id:1,sku_id:"a",stock:11}
{_id:2,sku_id:"b",stock:22}
{_id:3,sku_id:"c",stock:33}
{_id:4,sku_id:"d",stock:44}
{_id:5,sku_id:"e",stock:55}
{_id:6,sku_id:"a",stock:66}
{_id:7,sku_id:"b",stock:77}
{_id:8,sku_id:"c",stock:88}
{_id:9,sku_id:"d",stock:99}
*/
// mongoTemplate.mapReduce("article_info", "classpath:map.js",
// "classpath:reduce.js", options, ValueObject.class);
//方式1
// String map = "function(){" +
// "emit(this.sku_id,this.stock);" +
// "};";
// String reduce = "function(k,v){" +
// "return Array.sum(v);" +
// "};";
// mongoTemplate.mapReduce("a", map, reduce, Document.class).forEach(System.out::println);
//输出
// Document{{_id=a, value=77.0}}
// Document{{_id=b, value=99.0}}
// Document{{_id=c, value=121.0}}
// Document{{_id=d, value=143.0}}
// Document{{_id=e, value=55.0}}
//方式2
// String map = "function(){" +
// "emit(this.sku_id,this.stock);" +
// "};";
// String reduce = "function(k,v){" +
// "return {'k1':k,'v1':v,'sum':Array.sum(v)};" +
// "};";
// mongoTemplate.mapReduce("a", map, reduce, Document.class).forEach(System.out::println);
//输出
// Document{{_id=a, value=Document{{k1=a, v1=[11.0, 66.0], sum=77.0}}}}
// Document{{_id=b, value=Document{{k1=b, v1=[22.0, 77.0], sum=99.0}}}}
// Document{{_id=c, value=Document{{k1=c, v1=[33.0, 88.0], sum=121.0}}}}
// Document{{_id=d, value=Document{{k1=d, v1=[44.0, 99.0], sum=143.0}}}}
// Document{{_id=e, value=55.0}}
//方式3 -> query map reduce finalize
// String map = "function(){" +//this对应传入的表
// "emit(this.sku_id,this.stock);" +
// "};";
// String reduce = "function(k1,v1){" +//function(k1,v1) 对应 map的emit(k,v) -> k1=sku_id v1=stock
// "return {'k1':k1,'v1':v1,'sum':Array.sum(v1)};" +//添加sum字段记录总数
// "};";
// Query query=Query.query(Criteria.where("stock").ne(55));
// String finalize="function(k2,v2){" +// k2=k1 v2=reduce的ruturn
// "v2.avg=v.sum/v2.v1.length;" +//添加字段计算平均值
// "return v2;}";
// MapReduceOptions mapReduceOptions=new MapReduceOptions().finalizeFunction(finalize);
// mongoTemplate.mapReduce(query,"a",map,reduce,mapReduceOptions,Document.class).forEach(System.out::println);
//输出
// Document{{_id=a, value=Document{{k1=a, v1=[11.0, 66.0], sum=77.0, avg=38.5}}}}
// Document{{_id=b, value=Document{{k1=b, v1=[22.0, 77.0], sum=99.0, avg=49.5}}}}
// Document{{_id=c, value=Document{{k1=c, v1=[33.0, 88.0], sum=121.0, avg=60.5}}}}
// Document{{_id=d, value=Document{{k1=d, v1=[44.0, 99.0], sum=143.0, avg=71.5}}}}
}