概述
java中集成mongo的方法在上文已经详细阐述了,接下来就是API的具体使用方法
规范的使用方式是,对外封装好CRUD方法,内部通过mongoTemplate实现,具体对外提供的方法根据业务而定,但是最好不要直接使用mongoTemplate操作,当然这是在基于规范代码的条件下
mongoTemplate中封装了极为丰富的API方法,可以满足基本上所有的mongo命令操作,接下来开始逐个介绍
常用标签
@Id
用于标注在属性上,声明该字段为mongo文档的主键ID。当然如果不使用该标签,那么mongo会默认选择名称为ID的属性为mongo中的主键ID。如果自己不设置@Id主键,mongo会自动生成一个唯一主键,并且插入时效率远高于自己设置主键。
在实际业务中不建议自己设置主键,应交给mongo自己生成,自己可以设置一个业务id,如int型字段,用自己设置的业务id来维护相关联的表。
总结来讲,不建议自己生成主键ID,使用mongo自动生成主键ID最好,但是自己可以指定另一个属性为业务主键ID,因为通常来说,也不建议主键ID具有任何业务属性
@Document
用于标注在实体类上,通过collection属性声明该对象对应的集合
@Indexed
用于标注在属性上,为该属性创建索引。同时可指定该索引的唯一性,稀疏性,部分性,以及TTL
目前更推荐,在mongo命令行或通过mongo.indexOps创建索引
@CompoundIndex
用于标注在实体类上,声明创建该实体类对应集合的各种索引,目前更推荐,在mongo命令行或通过mongo.indexOps创建索引
具体用法
// 创建2dsphere球面索引@CompoundIndex(name = "location_index",def = "{'location'}:{'2dsphere'}")//创建复合索引@CompoundIndexes({@CompoundIndex(name = "id_name_idx", def = "{'id': 1, 'name': 1}", unique = true)})
@Field
用于标注在属性上,声明属性存储在mongo中的列名,可以不加,不加的话默认以参数名为列名
@Transient
用于标注在属性上,不会被录入到数据库中,也不在查询或聚合后映射到指定的属性上,只作为普通的javaBean属性。
@DBRef
关联另一个document对象。类似于mysql的表关联,但并不一样,mongo不会做级联的操作。
目前还没有用到这个操作
插入操作
与命令一样,增加操作也包括insert与save两种,下面介绍javaAPi使用方法
insert对象,指定ID
- 定义对象实体类 ```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; } ```
- 新增 ```java import cn.hutool.core.lang.Assert; import cn.hutool.json.JSONUtil; import com.ftc.mongotest.entity.Student; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Query;
/**
- @author 冯铁城 [17615007230@163.com]
- @date 2022-07-23 19:02:32
@describe: 增删改查测试 */ @SpringBootTest public class TestCrud {
@Autowired private MongoTemplate mongoTemplate;
@Test void testInsert() {
//1.指定_id字段Student student = new Student();student.setId("1");student.setName("ftc");student.setAge(18);mongoTemplate.insert(student);//2.校验Student result = mongoTemplate.findOne(new Query(), Student.class);Assert.isTrue(JSONUtil.toJsonStr(student).endsWith(JSONUtil.toJsonStr(result)));
} }
<a name="gAwwx"></a>### insert对象,不指定ID**需要注意的是,mongo自动生成的id是24位的字符,因此最好用String作为id的属性,不然会出现主键ID设置失败问题,进而引发主键ID重复!!!!!!!!!!!!!!!!**```java@Testvoid testInsert() {//1.指定_id字段Student student = new Student();student.setName("ftc");student.setAge(18);Student insert = mongoTemplate.insert(student);Console.log(insert);//2.校验Student result = mongoTemplate.findOne(new Query(), Student.class);Assert.notBlank(student.getId());Assert.isTrue(student.getName().equals(result.getName()));Assert.isTrue(student.getAge() == result.getAge());}
insert对象,指定集合
如果insert的对象通过标签指定集合,同时也没有在insert时指定集合,那么会创建一个该对象类名称的一个集合来存储该对象
@Testvoid testInsert() {//1.指定_id字段JSONObject obj = new JSONObject();obj.set("type", "自定义类型");obj = mongoTemplate.insert(obj, "student");Console.log(obj);}
save对象
save操作同样可以指定集合名称等,这里不做过多累述。只需知道save方法会覆盖更新即可
@Testvoid testSave() {//1.保存Student student = new Student();student.setId("1");student.setName("ftc");student.setAge(18);mongoTemplate.save(student);//2.校验Student result = mongoTemplate.findOne(new Query(), Student.class);Assert.isTrue("ftc".equals(result.getName()));//3.覆盖保存(更新)student.setName("马冬梅");mongoTemplate.save(student);//4.校验result = mongoTemplate.findOne(new Query(), Student.class);Assert.isTrue("马冬梅".equals(result.getName()));}
删除操作
删除操作通过remove()方法实现,可通过实体类删除对象、通过条件进行删除,也可全量删除,同样支持指定集合名称进行指定删除
@Testvoid testDelete() {//1.保存测试数据Student student = null;for (int i = 1; i <= 10; i++) {student = new Student();student.setId(i + "");student.setName(i + "ftc");student.setAge(18);mongoTemplate.insert(student);}//2.验证数据存入long count = mongoTemplate.count(new Query(), Student.class);Assert.isTrue(10 == count);//3.按条件删除,删除id=1DeleteResult remove = mongoTemplate.remove(new Query(Criteria.where("id").is("1")), Student.class);Assert.isTrue(1 == remove.getDeletedCount());Assert.isTrue(ObjectUtil.isNull(mongoTemplate.findById("1", Student.class)));//4.直接传入对象根据ID删除,删除id=10remove = mongoTemplate.remove(student);Assert.isTrue(1 == remove.getDeletedCount());Assert.isTrue(ObjectUtil.isNull(mongoTemplate.findById("10", Student.class)));//5.全量删除ExecutableRemoveOperation.ExecutableRemove<Student> removeAll = mongoTemplate.remove(Student.class);Assert.isTrue(8 == removeAll.all().getDeletedCount());//6.验证数据全部删除count = mongoTemplate.count(new Query(), Student.class);Assert.isTrue(0 == count);}
修改操作
基于Update更新
与命令一致,需要指定集合名称,条件,以及更新字段和更新属性(multi等)
@Testvoid testUpdate() {//1.保存测试数据Student student = null;for (int i = 1; i <= 10; i++) {student = new Student();student.setId(i + "");student.setName(i + "ftc");student.setAge(18);mongoTemplate.insert(student);}//2.验证数据存入long count = mongoTemplate.count(new Query(), Student.class);Assert.isTrue(10 == count);//3.按条件更新一条Query query = new Query(Criteria.where("id").is("1"));Update update = new Update();update.set("name", "夏洛");UpdateResult updateResult = mongoTemplate.updateFirst(query, update, Student.class);Assert.isTrue(1 == updateResult.getModifiedCount());Student result = mongoTemplate.findOne(query, Student.class);Assert.isTrue("夏洛".equals(result.getName()));//4.按条件更新全部query = new Query();update = new Update();update.set("name", "马冬梅");updateResult = mongoTemplate.updateMulti(query, update, Student.class);Assert.isTrue(10 == updateResult.getModifiedCount());List<Student> students = mongoTemplate.find(query, Student.class);students.forEach(s -> Assert.isTrue("马冬梅".equals(s.getName())));//5.另一种更新方式的写法update = new Update();update.set("name", "大傻春");ExecutableUpdateOperation.TerminatingUpdate<Student> apply = mongoTemplate.update(Student.class).apply(update);Assert.isTrue(10 == apply.all().getModifiedCount());students = mongoTemplate.find(query, Student.class);students.forEach(s -> Assert.isTrue("大傻春".equals(s.getName())));}
基于Save的操作
因为save操作目前不支持批量操作API,所以如果单条数据更新,使用save操作是可以的,批量操作还是使用update比较好
@Testvoid testUpdate() {//1.保存测试数据for (int i = 1; i <= 10; i++) {Student student = new Student();student.setId(i + "");student.setName(i + "ftc");student.setAge(18);mongoTemplate.insert(student);}//2.验证数据存入long count = mongoTemplate.count(new Query(), Student.class);Assert.isTrue(10 == count);//3.查询数据并修改属性List<Student> students = mongoTemplate.find(new Query(), Student.class);students.forEach(s -> s.setName("马冬梅"));//4.批量更新students.forEach(s -> mongoTemplate.save(s));//5.验证students = mongoTemplate.find(new Query(), Student.class);students.forEach(s -> Assert.isTrue("马冬梅".equals(s.getName())));}
原子性更新操作
在引入wiredTiger引擎后,mongo实现了对单文档操作的原子性
在javaApi中,通过findAndModify方法进行文档的原子性更新
需要注意的是,该方法只会操作一个文档!!!!!因此如果query的结果集为多个文档,那么最终也只会操作结果集的第一个文档!!!!!@Testvoid testUpdate() {//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(Criteria.where("age").gt(5));Update update = new Update();update.set("name", "马冬梅");//4.查询数据并修改属性Student andModify = mongoTemplate.findAndModify(query, update, Student.class);//5.验证只有一条数据被修改andModify = mongoTemplate.findById(andModify.getId(), Student.class);Assert.isTrue("马冬梅".equals(andModify.getName()));//6.验证其他数据没有被修改List<Student> students = mongoTemplate.find(new Query(Criteria.where("id").ne(andModify.getId())), Student.class);students.forEach(s -> Assert.isTrue(!"马冬梅".equals(s.getName())));}
查询操作
基础的查询操作
包括根据ID查询,查询单条数据,查询批量数据,集合全量查询,去重查询等
需要注意的是,去重查询必须指定去重字段,并且返回的结果集只能是指定的字段@Testvoid 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.根据ID查询单个数据Student result = mongoTemplate.findById(1, Student.class);Assert.isTrue(1 == result.getAge());//4.根据条件查询单个数据result = mongoTemplate.findOne(new Query(Criteria.where("id").is(2)), Student.class);Assert.isTrue(2 == result.getAge());//5.根据条件查询批量数据List<Student> results = mongoTemplate.find(new Query(Criteria.where("id").gt(5)), Student.class);Assert.isTrue(5 == results.size());//6.集合全量查询results = mongoTemplate.findAll(Student.class);Assert.isTrue(10 == results.size());//7.新增一条重复age数据Student repeatStudent = new Student();repeatStudent.setId(11);repeatStudent.setAge(1);repeatStudent.setName("ftccccc");mongoTemplate.insert(repeatStudent);count = mongoTemplate.count(new Query(), Student.class);Assert.isTrue(11 == count);//8.去重查询List<Integer> ages = mongoTemplate.findDistinct(new Query(), "age", Student.class, Integer.class);Assert.isTrue(10 == ages.size());}
条件查询
@Testvoid 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(Criteria.where("id").is(1));List<Student> students = mongoTemplate.find(query, Student.class);Assert.isTrue(1 == students.size());Assert.isTrue(1 == students.get(0).getAge());//4.小于查询query = new Query(Criteria.where("age").lt(5));students = mongoTemplate.find(query, Student.class);Assert.isTrue(4 == students.size());//5.小于等于查询query = new Query(Criteria.where("age").lte(5));students = mongoTemplate.find(query, Student.class);Assert.isTrue(5 == students.size());//6.大于查询query = new Query(Criteria.where("age").gt(7));students = mongoTemplate.find(query, Student.class);Assert.isTrue(3 == students.size());//7.大于等于查询query = new Query(Criteria.where("age").gte(7));students = mongoTemplate.find(query, Student.class);Assert.isTrue(4 == students.size());//8.不等于查询query = new Query(Criteria.where("id").ne(5));students = mongoTemplate.find(query, Student.class);Assert.isTrue(9 == students.size());//9.in查询query = new Query(Criteria.where("age").in(1, 2, 3));students = mongoTemplate.find(query, Student.class);Assert.isTrue(3 == students.size());//10.not in查询query = new Query(Criteria.where("age").nin(CollUtil.newArrayList(1, 2, 3)));students = mongoTemplate.find(query, Student.class);Assert.isTrue(7 == students.size());//11.and查询query = new Query(Criteria.where("id").is(1).and("age").is(2));students = mongoTemplate.find(query, Student.class);Assert.isTrue(0 == students.size());//12.or查询query = new Query(new Criteria().orOperator(Criteria.where("id").is(2), Criteria.where("id").is(3)));students = mongoTemplate.find(query, Student.class);Assert.isTrue(2 == students.size());//13.and与or结合查询query = new Query(Criteria.where("id").is(2).orOperator(Criteria.where("age").is(2),Criteria.where("age").is(3)));students = mongoTemplate.find(query, Student.class);Assert.isTrue(1 == students.size());}
原子性查询操作
包括批量查询并删除、查找并删除、查询并修改、查询并替换
需要注意的是,非批量原子操作,即使根据query遍历的结果集为多条,也只是默认原子性操作结果集的第一条数据!!!!!@Testvoid 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(Criteria.where("id").is(1));List<Student> students = mongoTemplate.findAllAndRemove(query, Student.class);Assert.isTrue(1 == students.size());count = mongoTemplate.count(new Query(), Student.class);Assert.isTrue(9 == count);//4.原子性查询并修改query = new Query(Criteria.where("id").is(2));Update update = new Update();update.set("name", "马冬梅");mongoTemplate.findAndModify(query, update, Student.class);Student student = mongoTemplate.findOne(query, Student.class);Assert.isTrue("马冬梅".equals(student.getName()));//5.原子性查询并删除query = new Query(Criteria.where("id").is(3));Student andRemove = mongoTemplate.findAndRemove(query, Student.class);student = mongoTemplate.findOne(query, Student.class);Assert.isNull(student);//6.原子性查询并替换文档Student studentReplace = new Student();studentReplace.setId(4);studentReplace.setAge(100);studentReplace.setName("替换对象");query = new Query(Criteria.where("id").is(4));mongoTemplate.findAndReplace(query, studentReplace, "student");Student result = mongoTemplate.findOne(query, Student.class);Assert.isTrue(100 == result.getAge());}
