概述

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创建索引
具体用法

  1. // 创建2dsphere球面索引
  2. @CompoundIndex(name = "location_index",def = "{'location'}:{'2dsphere'}")
  3. //创建复合索引
  4. @CompoundIndexes({
  5. @CompoundIndex(name = "id_name_idx", def = "{'id': 1, 'name': 1}", unique = true)
  6. })

@Field

用于标注在属性上,声明属性存储在mongo中的列名,可以不加,不加的话默认以参数名为列名

@Transient

用于标注在属性上,不会被录入到数据库中,也不在查询或聚合后映射到指定的属性上,只作为普通的javaBean属性。

@DBRef

关联另一个document对象。类似于mysql的表关联,但并不一样,mongo不会做级联的操作。
目前还没有用到这个操作

插入操作

与命令一样,增加操作也包括insert与save两种,下面介绍javaAPi使用方法

insert对象,指定ID

  1. 定义对象实体类 ```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. 新增 ```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. //1.指定_id字段
    2. Student student = new Student();
    3. student.setId("1");
    4. student.setName("ftc");
    5. student.setAge(18);
    6. mongoTemplate.insert(student);
    7. //2.校验
    8. Student result = mongoTemplate.findOne(new Query(), Student.class);
    9. Assert.isTrue(JSONUtil.toJsonStr(student).endsWith(JSONUtil.toJsonStr(result)));

    } }

    1. <a name="gAwwx"></a>
    2. ### insert对象,不指定ID
    3. **需要注意的是,mongo自动生成的id是24位的字符,因此最好用String作为id的属性,不然会出现主键ID设置失败问题,进而引发主键ID重复!!!!!!!!!!!!!!!!**
    4. ```java
    5. @Test
    6. void testInsert() {
    7. //1.指定_id字段
    8. Student student = new Student();
    9. student.setName("ftc");
    10. student.setAge(18);
    11. Student insert = mongoTemplate.insert(student);
    12. Console.log(insert);
    13. //2.校验
    14. Student result = mongoTemplate.findOne(new Query(), Student.class);
    15. Assert.notBlank(student.getId());
    16. Assert.isTrue(student.getName().equals(result.getName()));
    17. Assert.isTrue(student.getAge() == result.getAge());
    18. }

    image.png

    insert对象,指定集合

    如果insert的对象通过标签指定集合,同时也没有在insert时指定集合,那么会创建一个该对象类名称的一个集合来存储该对象

    1. @Test
    2. void testInsert() {
    3. //1.指定_id字段
    4. JSONObject obj = new JSONObject();
    5. obj.set("type", "自定义类型");
    6. obj = mongoTemplate.insert(obj, "student");
    7. Console.log(obj);
    8. }

    image.png

    save对象

    save操作同样可以指定集合名称等,这里不做过多累述。只需知道save方法会覆盖更新即可

    1. @Test
    2. void testSave() {
    3. //1.保存
    4. Student student = new Student();
    5. student.setId("1");
    6. student.setName("ftc");
    7. student.setAge(18);
    8. mongoTemplate.save(student);
    9. //2.校验
    10. Student result = mongoTemplate.findOne(new Query(), Student.class);
    11. Assert.isTrue("ftc".equals(result.getName()));
    12. //3.覆盖保存(更新)
    13. student.setName("马冬梅");
    14. mongoTemplate.save(student);
    15. //4.校验
    16. result = mongoTemplate.findOne(new Query(), Student.class);
    17. Assert.isTrue("马冬梅".equals(result.getName()));
    18. }

    删除操作

    删除操作通过remove()方法实现,可通过实体类删除对象、通过条件进行删除,也可全量删除,同样支持指定集合名称进行指定删除

    1. @Test
    2. void testDelete() {
    3. //1.保存测试数据
    4. Student student = null;
    5. for (int i = 1; i <= 10; i++) {
    6. student = new Student();
    7. student.setId(i + "");
    8. student.setName(i + "ftc");
    9. student.setAge(18);
    10. mongoTemplate.insert(student);
    11. }
    12. //2.验证数据存入
    13. long count = mongoTemplate.count(new Query(), Student.class);
    14. Assert.isTrue(10 == count);
    15. //3.按条件删除,删除id=1
    16. DeleteResult remove = mongoTemplate.remove(new Query(Criteria.where("id").is("1")), Student.class);
    17. Assert.isTrue(1 == remove.getDeletedCount());
    18. Assert.isTrue(ObjectUtil.isNull(mongoTemplate.findById("1", Student.class)));
    19. //4.直接传入对象根据ID删除,删除id=10
    20. remove = mongoTemplate.remove(student);
    21. Assert.isTrue(1 == remove.getDeletedCount());
    22. Assert.isTrue(ObjectUtil.isNull(mongoTemplate.findById("10", Student.class)));
    23. //5.全量删除
    24. ExecutableRemoveOperation.ExecutableRemove<Student> removeAll = mongoTemplate.remove(Student.class);
    25. Assert.isTrue(8 == removeAll.all().getDeletedCount());
    26. //6.验证数据全部删除
    27. count = mongoTemplate.count(new Query(), Student.class);
    28. Assert.isTrue(0 == count);
    29. }

    修改操作

    基于Update更新

    与命令一致,需要指定集合名称,条件,以及更新字段和更新属性(multi等)

    1. @Test
    2. void testUpdate() {
    3. //1.保存测试数据
    4. Student student = null;
    5. for (int i = 1; i <= 10; i++) {
    6. student = new Student();
    7. student.setId(i + "");
    8. student.setName(i + "ftc");
    9. student.setAge(18);
    10. mongoTemplate.insert(student);
    11. }
    12. //2.验证数据存入
    13. long count = mongoTemplate.count(new Query(), Student.class);
    14. Assert.isTrue(10 == count);
    15. //3.按条件更新一条
    16. Query query = new Query(Criteria.where("id").is("1"));
    17. Update update = new Update();
    18. update.set("name", "夏洛");
    19. UpdateResult updateResult = mongoTemplate.updateFirst(query, update, Student.class);
    20. Assert.isTrue(1 == updateResult.getModifiedCount());
    21. Student result = mongoTemplate.findOne(query, Student.class);
    22. Assert.isTrue("夏洛".equals(result.getName()));
    23. //4.按条件更新全部
    24. query = new Query();
    25. update = new Update();
    26. update.set("name", "马冬梅");
    27. updateResult = mongoTemplate.updateMulti(query, update, Student.class);
    28. Assert.isTrue(10 == updateResult.getModifiedCount());
    29. List<Student> students = mongoTemplate.find(query, Student.class);
    30. students.forEach(s -> Assert.isTrue("马冬梅".equals(s.getName())));
    31. //5.另一种更新方式的写法
    32. update = new Update();
    33. update.set("name", "大傻春");
    34. ExecutableUpdateOperation.TerminatingUpdate<Student> apply = mongoTemplate.update(Student.class).apply(update);
    35. Assert.isTrue(10 == apply.all().getModifiedCount());
    36. students = mongoTemplate.find(query, Student.class);
    37. students.forEach(s -> Assert.isTrue("大傻春".equals(s.getName())));
    38. }

    基于Save的操作

    因为save操作目前不支持批量操作API,所以如果单条数据更新,使用save操作是可以的,批量操作还是使用update比较好

    1. @Test
    2. void testUpdate() {
    3. //1.保存测试数据
    4. for (int i = 1; i <= 10; i++) {
    5. Student student = new Student();
    6. student.setId(i + "");
    7. student.setName(i + "ftc");
    8. student.setAge(18);
    9. mongoTemplate.insert(student);
    10. }
    11. //2.验证数据存入
    12. long count = mongoTemplate.count(new Query(), Student.class);
    13. Assert.isTrue(10 == count);
    14. //3.查询数据并修改属性
    15. List<Student> students = mongoTemplate.find(new Query(), Student.class);
    16. students.forEach(s -> s.setName("马冬梅"));
    17. //4.批量更新
    18. students.forEach(s -> mongoTemplate.save(s));
    19. //5.验证
    20. students = mongoTemplate.find(new Query(), Student.class);
    21. students.forEach(s -> Assert.isTrue("马冬梅".equals(s.getName())));
    22. }

    原子性更新操作

    在引入wiredTiger引擎后,mongo实现了对单文档操作的原子性
    在javaApi中,通过findAndModify方法进行文档的原子性更新
    需要注意的是,该方法只会操作一个文档!!!!!因此如果query的结果集为多个文档,那么最终也只会操作结果集的第一个文档!!!!!

    1. @Test
    2. void testUpdate() {
    3. //1.保存测试数据
    4. for (int i = 1; i <= 10; i++) {
    5. Student student = new Student();
    6. student.setId(i + "");
    7. student.setName(i + "ftc");
    8. student.setAge(i);
    9. mongoTemplate.insert(student);
    10. }
    11. //2.验证数据存入
    12. long count = mongoTemplate.count(new Query(), Student.class);
    13. Assert.isTrue(10 == count);
    14. //3.定义更新属性
    15. Query query = new Query(Criteria.where("age").gt(5));
    16. Update update = new Update();
    17. update.set("name", "马冬梅");
    18. //4.查询数据并修改属性
    19. Student andModify = mongoTemplate.findAndModify(query, update, Student.class);
    20. //5.验证只有一条数据被修改
    21. andModify = mongoTemplate.findById(andModify.getId(), Student.class);
    22. Assert.isTrue("马冬梅".equals(andModify.getName()));
    23. //6.验证其他数据没有被修改
    24. List<Student> students = mongoTemplate.find(new Query(Criteria.where("id").ne(andModify.getId())), Student.class);
    25. students.forEach(s -> Assert.isTrue(!"马冬梅".equals(s.getName())));
    26. }

    查询操作

    基础的查询操作

    包括根据ID查询,查询单条数据,查询批量数据,集合全量查询,去重查询等
    需要注意的是,去重查询必须指定去重字段,并且返回的结果集只能是指定的字段

    1. @Test
    2. void testSelect() {
    3. //1.保存测试数据
    4. for (int i = 1; i <= 10; i++) {
    5. Student student = new Student();
    6. student.setId(i);
    7. student.setName(i + "ftc");
    8. student.setAge(i);
    9. mongoTemplate.insert(student);
    10. }
    11. //2.验证数据存入
    12. long count = mongoTemplate.count(new Query(), Student.class);
    13. Assert.isTrue(10 == count);
    14. //3.根据ID查询单个数据
    15. Student result = mongoTemplate.findById(1, Student.class);
    16. Assert.isTrue(1 == result.getAge());
    17. //4.根据条件查询单个数据
    18. result = mongoTemplate.findOne(new Query(Criteria.where("id").is(2)), Student.class);
    19. Assert.isTrue(2 == result.getAge());
    20. //5.根据条件查询批量数据
    21. List<Student> results = mongoTemplate.find(new Query(Criteria.where("id").gt(5)), Student.class);
    22. Assert.isTrue(5 == results.size());
    23. //6.集合全量查询
    24. results = mongoTemplate.findAll(Student.class);
    25. Assert.isTrue(10 == results.size());
    26. //7.新增一条重复age数据
    27. Student repeatStudent = new Student();
    28. repeatStudent.setId(11);
    29. repeatStudent.setAge(1);
    30. repeatStudent.setName("ftccccc");
    31. mongoTemplate.insert(repeatStudent);
    32. count = mongoTemplate.count(new Query(), Student.class);
    33. Assert.isTrue(11 == count);
    34. //8.去重查询
    35. List<Integer> ages = mongoTemplate.findDistinct(new Query(), "age", Student.class, Integer.class);
    36. Assert.isTrue(10 == ages.size());
    37. }

    条件查询

    1. @Test
    2. void testSelect() {
    3. //1.保存测试数据
    4. for (int i = 1; i <= 10; i++) {
    5. Student student = new Student();
    6. student.setId(i);
    7. student.setName(i + "ftc");
    8. student.setAge(i);
    9. mongoTemplate.insert(student);
    10. }
    11. //2.验证数据存入
    12. long count = mongoTemplate.count(new Query(), Student.class);
    13. Assert.isTrue(10 == count);
    14. //3.等值查询
    15. Query query = new Query(Criteria.where("id").is(1));
    16. List<Student> students = mongoTemplate.find(query, Student.class);
    17. Assert.isTrue(1 == students.size());
    18. Assert.isTrue(1 == students.get(0).getAge());
    19. //4.小于查询
    20. query = new Query(Criteria.where("age").lt(5));
    21. students = mongoTemplate.find(query, Student.class);
    22. Assert.isTrue(4 == students.size());
    23. //5.小于等于查询
    24. query = new Query(Criteria.where("age").lte(5));
    25. students = mongoTemplate.find(query, Student.class);
    26. Assert.isTrue(5 == students.size());
    27. //6.大于查询
    28. query = new Query(Criteria.where("age").gt(7));
    29. students = mongoTemplate.find(query, Student.class);
    30. Assert.isTrue(3 == students.size());
    31. //7.大于等于查询
    32. query = new Query(Criteria.where("age").gte(7));
    33. students = mongoTemplate.find(query, Student.class);
    34. Assert.isTrue(4 == students.size());
    35. //8.不等于查询
    36. query = new Query(Criteria.where("id").ne(5));
    37. students = mongoTemplate.find(query, Student.class);
    38. Assert.isTrue(9 == students.size());
    39. //9.in查询
    40. query = new Query(Criteria.where("age").in(1, 2, 3));
    41. students = mongoTemplate.find(query, Student.class);
    42. Assert.isTrue(3 == students.size());
    43. //10.not in查询
    44. query = new Query(Criteria.where("age").nin(CollUtil.newArrayList(1, 2, 3)));
    45. students = mongoTemplate.find(query, Student.class);
    46. Assert.isTrue(7 == students.size());
    47. //11.and查询
    48. query = new Query(Criteria.where("id").is(1).and("age").is(2));
    49. students = mongoTemplate.find(query, Student.class);
    50. Assert.isTrue(0 == students.size());
    51. //12.or查询
    52. query = new Query(new Criteria().orOperator(
    53. Criteria.where("id").is(2), Criteria.where("id").is(3))
    54. );
    55. students = mongoTemplate.find(query, Student.class);
    56. Assert.isTrue(2 == students.size());
    57. //13.and与or结合查询
    58. query = new Query(Criteria.where("id").is(2).orOperator(
    59. Criteria.where("age").is(2),
    60. Criteria.where("age").is(3)
    61. ));
    62. students = mongoTemplate.find(query, Student.class);
    63. Assert.isTrue(1 == students.size());
    64. }

    原子性查询操作

    包括批量查询并删除、查找并删除、查询并修改、查询并替换
    需要注意的是,非批量原子操作,即使根据query遍历的结果集为多条,也只是默认原子性操作结果集的第一条数据!!!!!

    1. @Test
    2. void testSelect() {
    3. //1.保存测试数据
    4. for (int i = 1; i <= 10; i++) {
    5. Student student = new Student();
    6. student.setId(i);
    7. student.setName(i + "ftc");
    8. student.setAge(i);
    9. mongoTemplate.insert(student);
    10. }
    11. //2.验证数据存入
    12. long count = mongoTemplate.count(new Query(), Student.class);
    13. Assert.isTrue(10 == count);
    14. //3.原子性查询并删除批量
    15. Query query = new Query(Criteria.where("id").is(1));
    16. List<Student> students = mongoTemplate.findAllAndRemove(query, Student.class);
    17. Assert.isTrue(1 == students.size());
    18. count = mongoTemplate.count(new Query(), Student.class);
    19. Assert.isTrue(9 == count);
    20. //4.原子性查询并修改
    21. query = new Query(Criteria.where("id").is(2));
    22. Update update = new Update();
    23. update.set("name", "马冬梅");
    24. mongoTemplate.findAndModify(query, update, Student.class);
    25. Student student = mongoTemplate.findOne(query, Student.class);
    26. Assert.isTrue("马冬梅".equals(student.getName()));
    27. //5.原子性查询并删除
    28. query = new Query(Criteria.where("id").is(3));
    29. Student andRemove = mongoTemplate.findAndRemove(query, Student.class);
    30. student = mongoTemplate.findOne(query, Student.class);
    31. Assert.isNull(student);
    32. //6.原子性查询并替换文档
    33. Student studentReplace = new Student();
    34. studentReplace.setId(4);
    35. studentReplace.setAge(100);
    36. studentReplace.setName("替换对象");
    37. query = new Query(Criteria.where("id").is(4));
    38. mongoTemplate.findAndReplace(query, studentReplace, "student");
    39. Student result = mongoTemplate.findOne(query, Student.class);
    40. Assert.isTrue(100 == result.getAge());
    41. }