MongoDB 是一个基于分布式文件存储的数据库,由 C++ 编写,它是可扩展的高性能数据存储解决方案。来看一下 MongoDB 官网对于 MongoDB 的简单介绍。
一、MongoDB 使用简介
在 MongoDB 中,它的一些名词与关系型数据库的名词并不相同,我引入一张图供大家进行参考,如下图所示。
在 MongoDB 中,集合就相当于关系型数据库中表的概念,但是它和表又不一样。因为同一个集合下可以存储不同的数据,且集合与集合之间不存在关联关系。它也没有列的概念,在使用 MongoDB 时无需提前定义它的列与数据类型(尽管实际使用中还是会通过实体类定义一下),没有列的概念,那么每一行的数据可以存储的就是意义上完全不同的数据,比如商品详情信息,可以把手机和电脑放入一个集合,但是手机和电脑的参数完全不同,对于 MongoDB 而言是没有问题的。
在对 MongoDB 做完简单的介绍后,再介绍几个 MongoDB 常用的命令:
1.查看 MongoDB 中的数据库
show dbs
2.选择数据库
use local
3.查看数据库中的集合
show collections
4.查看集合中的全部数据
db.startup_log.find()
更多的使用命令,可以参考 MongoDB 的文件进行学习了解。
二、在 SpringBoot 中引入依赖
在 SpringBoot 项目中使用 MongoDB,首先需要引入 MongoDB 的依赖,通过在 POM 文件中引入 MongoDB 的依赖坐标,即可将操作 MongoDB 的类库整合入 SpringBoot 项目当中,相关依赖如下:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency>
三、添加配置
引入依赖之后,需要在配置文件中添加 MongoDB 的地址,如同我们使用 MySQL 一样需要给出它的地址。
spring: data: mongodb: uri: mongodb://127.0.0.1:27017/test
1. uri: mongodb://127.0.0.1:27017/test
在上面的 uri 中,test 指定了我们 Demo 中要操作的数据库。
四、定义对应 MongoDB 中集合的实体类
操作 MySQL 时,我们会将 MySQL 的表在项目中定义一个对应的实体类,操作 MongoDB 的集合也需要定义一个对应的实体类。这里定义一个 Student 的实体类作为 Demo 中的实体类来进行操作。
@Data @Document("Student") public class Student { @Id private String id; private String name; private Integer age; private String email; }
在实体类上添加注解 @Document,@Document 中给出的是集合的名称。注解 @Id 会将该字段与 MongoDB 生成的 _id 进行关联。
在具体操作 MongoDB 时可以通过 MongoTemplate 来进行操作,也可以通过 MongoRepository 来进行操作。下面我们将介绍如何使用 MongoTemplate 来完成对 MongoDB 的 CRUD 操作。
五、使用 MongoTemplate 完成 CRUD
MongoTemplate 基于 Spring 容器提供了一组对 MongoDB 操作的基本方法,只要将 MongoTemplate 注入到需要使用的类中,即可直接使用。
1.注入 MongoTemplate
创建一个测试类,通过 @Autowired 将 MongoTemplate 进行注入,代码如下。
@Autowired private MongoTemplate mongoTemplate;
2.添加操作
在注入 MongoTemplate 后,我们即可在测试类中完成 CRUD 的操作,先来完成一个添加数据的操作,代码如下:
/** * 添加操作 */ @Test void create() { for (int i = 0; i < 10; i ++) { Student student = new Student(); student.setAge(20 + i); student.setName("test" + i); student.setEmail(i + "12345@qq.com"); Student insert = mongoTemplate.insert(student); System.out.println(insert); } }
通过 MongoTemplate 的 insert 方法,即可完成数据的插入操作。
执行上面的测试代码后,我们通过 MongoDB 的客户端来查看一下我们添加的数据。首先通过 show dbs 命令来查看 MongoDB 中的数据库,可以看到多了一个 test 数据库,如下图所示:
然后,使用 use 选择该数据库,使用 show collections 查看 test 下的集合,可以看到在 test 数据库下自动创建了一个 Student 的集合,如下图所示:
可以看到,在我们执行上面的方法之前,并没有去创建 test 数据库,也没有创建 Student 集合。执行了上面的代码后,会自动创建 test 数据库和 Student 集合,并且在 Student 集合中插入了 10 条文档。
3.查询集合中的所有记录
上面完成了文档数据插入的操作,现在通过 MongoTemplate 来将其全部查出,代码如下:
/** * 查询表中所有记录 */ @Test void findAll() { List<Student> all = mongoTemplate.findAll(Student.class); all.forEach(System.out::println); }
通过 MongoTemplate 的 findAll 方法可以查询指定集合下的所有文档。
执行上面的代码后,在控制台会输出 Student 集合中的全部文档,输出内容如下所示。
Student(id=614c43b77fbbb70ee5016e52, name=test0, age=20, email=012345@qq.com) Student(id=614c43b77fbbb70ee5016e53, name=test1, age=21, email=112345@qq.com) Student(id=614c43b77fbbb70ee5016e54, name=test2, age=22, email=212345@qq.com) Student(id=614c43b77fbbb70ee5016e55, name=test3, age=23, email=312345@qq.com) Student(id=614c43b77fbbb70ee5016e56, name=test4, age=24, email=412345@qq.com) Student(id=614c43b77fbbb70ee5016e57, name=test5, age=25, email=512345@qq.com) Student(id=614c43b77fbbb70ee5016e58, name=test6, age=26, email=612345@qq.com) Student(id=614c43b77fbbb70ee5016e59, name=test7, age=27, email=712345@qq.com) Student(id=614c43b77fbbb70ee5016e5a, name=test8, age=28, email=812345@qq.com) Student(id=614c43b77fbbb70ee5016e5b, name=test9, age=29, email=912345@qq.com)
从输出中可以看出,MongoDB 为我们生成了 id,通过这个 id 我们可以唯一的确定一条数据。
4.通过 id 查询指定的文档
通常,我们在查询指定的某条数据时会通过 id 进行查询,在添加数据时,可以看到 MongoDB 为我们自动生成了 id,名为 _id,只要通过 MongoTemplate 的 findById 方法,并传入相应的 id 值即可进行查询,代码如下:
/** * 根据 id查询 */ @Test void findById() { Student byId = mongoTemplate.findById("614c43b77fbbb70ee5016e52", Student.class); System.out.println(byId); }
从上面的代码中可以看到,通过 MongoTemplate 的 findById 可以获取指定 id 的文档。
5.条件查询
MongoDB 支持非常强大的查询功能,这里简单的完成一个条件查询。代码如下:
/** * 条件查询 */ @Test void findUserList() { // name = test0 and age = 20 Query query = new Query( Criteria.where("name").is("test0") .and("age").is(20) ); List<Student> users = mongoTemplate.find(query, Student.class); users.forEach(System.out::println); }
在上面的代码中,Criteria 是 MongoTemplate 的标准查询接口,它可以把多个查询条件通过链式操作进行拼接,然后通过 Query 可以构建查询语句,上面的查询相当于如下 SQL 语句:
select * from student where name = 'test0' and age = 20
再来完成一个 or 的查询,代码如下:
/** * 条件查询 */ @Test void findUserList() { Query query = new Query( new Criteria().orOperator( Criteria.where("name").is("test0").and("age").is(20), Criteria.where("age").gt(25) ) ); List<Student> users = mongoTemplate.find(query, Student.class); users.forEach(System.out::println); }
注意上面代码中关于 Criteria 的写法,上面的代码,相当于如下 SQL 语句:
select * from student where (name = 'test0' and age = 20) or (age > 25)
or 查询的输出结果如下:
Student(id=614c43b77fbbb70ee5016e52, name=test0, age=20, email=012345@qq.com) Student(id=614c43b77fbbb70ee5016e58, name=test6, age=26, email=612345@qq.com) Student(id=614c43b77fbbb70ee5016e59, name=test7, age=27, email=712345@qq.com) Student(id=614c43b77fbbb70ee5016e5a, name=test8, age=28, email=812345@qq.com) Student(id=614c43b77fbbb70ee5016e5b, name=test9, age=29, email=912345@qq.com)
通过上面的输出可以验证 or 查询的写法是正确的。
6.模糊查询
MongoDB 的模糊查询可以使用正则表达式来进行完成,代码如下:
/** * 模糊查询 */ @Test void findLikeUserList() { // name like test and age = 20 String name = "est"; String regex = String.format("%s%s%s", "^.*", name, ".*$"); Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); Query query = new Query( Criteria.where("name").regex(pattern) .and("age").is(20) ); List<Student> users = mongoTemplate.find(query, Student.class); users.forEach(System.out::println); }
上面的代码中,在 Criteria.where 后面使用了 regex,而不是 is,就可以使用正则表达式来进行查询。上面的模糊查询相当于是 SQL 语句中的 like,由于我们的 name 字段中都能匹配到 est 字符串,这个例子也就没有太多的意义了。
7.分页查询
在 MySQL 中进行数据的分页查询,一般需要给接口传入页码和每页记录的条数,当然也需要传入一些查询条件。对于 MongoDB 而言,传入接口的数据也是一样的。
/** * 分页查询 */ @Test void findPageUserList() { int pageNo = 2; int pageSize = 3; // 条件构件 Query query = new Query( Criteria.where("age").gt(23) ); // 分页构件 // 查询记录数 long count = mongoTemplate.count(query, Student.class); // 分页 List<Student> users = mongoTemplate.find( query.skip((pageNo - 1) * pageSize) .limit(pageSize), Student.class); System.out.println(count); users.forEach(System.out::println); }
分页查询通过 query 的 skip 和 limit 进行完成,此处也类似于 MySQL 的 limit 的用法。上面的代码中,我们的分页每页显示 3 条,当前页是第 2 页。在代码的第 16 行,通过 MongoTemplate 的 count 获取了满足条件的记录总数,以上代码输出的数据如下:
6 Student(id=614c43b77fbbb70ee5016e59, name=test7, age=27, email=712345@qq.com) Student(id=614c43b77fbbb70ee5016e5a, name=test8, age=28, email=812345@qq.com) Student(id=614c43b77fbbb70ee5016e5b, name=test9, age=29, email=912345@qq.com)
在我们的条件中,我们查询 age 大于 23 的,也就是从 24 到 29,一共有 6 条数据。前 3 条是 24 到 26,那么此处的数据显示是正确的。
8.修改数据
修改数据时首先对数据进行查询,然后设置需要修改的值,进行数据的更新。
/** * 修改 */ @Test void updateUser() { // 根据id查询 Student user = mongoTemplate.findById("614c43b77fbbb70ee5016e59", Student.class); // 设置修改值 assert user != null; user.setName("zhangsan"); user.setAge(30); user.setEmail("haha@qq.com"); Query query = new Query(Criteria.where("_id").is(user.getId())); Update update = new Update(); update.set("name", user.getName()); update.set("age", user.getAge()); update.set("email", user.getEmail()); // 调用方法实现修改 UpdateResult upsert = mongoTemplate.upsert(query, update, Student.class); System.out.println(upsert.getModifiedCount()); }
通过 MongoTemplate 的 upsert 方法可以对数据进行修改,修改后的数据如下图:
在上面的代码中,如果只需要更新 name 或 age 或 email 中的一个,那么只需要设置其中一个值即可,无需全部进行 set。
9.删除数据
删除操作同样通过 Query 类构造要删除的条件,然后调用 remove 方法进行删除即可。
/** * 删除操作 */ @Test void deleteUser(){ Query query = new Query(Criteria.where("_id").is("614c43b77fbbb70ee5016e59")); DeleteResult remove = mongoTemplate.remove(query, Student.class); System.out.println(remove.getDeletedCount()); }
通过 MongoTemplate 的 remove 方法,我们删除了一条数据,通过 db.Student.find() 命令进行查看,可以看到刚才更新过的 zhangsan 那条数据已经被删除了。调用 remove 方法后,会返回 DeleteResult 对象,通过该对象调用 getDeletedCount 方法可以获得删除的记录数。
六、总结
MongoDB 已经被越来越多的使用,它适合于对大量的、无固定数据结构的数据进行存储。本文简单的介绍了通过使用 MongoTemplate 来对 MongoDB 进行 CRUD 的操作。下次来介绍通过 MongoRepository 对 MongoDB 的 CRUD 操作。