
前言
MongoDB 是一种流行的 NoSQL 数据库,适合存储大量的非结构化数据。MongoTemplate 是 Spring Data MongoDB 中的一个核心组件,它提供了一组丰富的 API 来与 MongoDB 进行交互。它封装了许多常见的数据库操作,使开发者能够轻松执行 CRUD 操作、处理复杂查询和聚合等。本文将详细介绍 MongoTemplate 的基本用法,包含语法介绍和具体的使用示例。
一、初识 MongoTemplate
1.1 Spring Data MongoDB 简介
Spring Data MongoDB 是 Spring Data 项目的一部分,提供了与 MongoDB 文档数据库的集成。Spring Data MongoDB 的关键功能是一个以 POJO 为中心的模型,用于与 MongoDB 数据集合交互,并轻松地编写一个存储库风格的数据访问层。在 Spring Boot 项目中使用 MongoDB,首先需要引入 MongoDB 的依赖,通过在 POM 文件中引入 MongoDB 的依赖坐标,即可将操作 MongoDB 的类库整合入 SpringBoot 项目当中,相关依赖如下:
xml
<!-- springboot 整合 mongodb -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>x.y.z</version>
</dependency>
1.2 MongoTemplate 简介
MongoTemplate 类位于 org.springframework.data.mongodb.core 包中,是 Spring 支持 MongoDB 的高级抽象类,为与 MongoDB 数据库交互提供了丰富的功能集。其封装了 MongoClient,提供了一个更高层次的模板方法 API 来简化 MongoDB 的操作。通过相对简单的方法来执行创建、更新、删除和查询 MongoDB 等操作,同时集成了 Spring 的转换和异常处理机制。使用 MongoTemplate,不需要关心低层次的数据库连接和错误处理。而且 MongoTemplate 支持将 Java 对象映射到 MongoDB 文档,并提供了一组方法,用于在 Java 对象和 MongoDB 文档之间进行转换,这样可以方便地操作和管理数据。
【注意】MongoTemplate 是线程安全的,一旦配置好就可以在多个实例中重复使用(多线程环境中)。
我们先看看 MongoTemplate 的构造方法,它有几个重载的构造函数,如下所示:
java
/**
* 根据 MongoClient 对象和要对其进行操作的默认数据库名称去实例化 MongoTemplate。
*/
public MongoTemplate(MongoClient mongoClient, String databaseName) {
}
/**
* 根据 MongoDatabaseFactory 对象实例化 MongoTemplate,
^ MongoDatabaseFactory 封装了 MongoClient 对象、数据库名称、用户名和密码等信息。
*/
public MongoTemplate(MongoDatabaseFactory mongoDbFactory) {
}
/**
* 用于对象和文档映射的 MongoConverter 接口实现去实例化 MongoTemplate
*/
public MongoTemplate(MongoDatabaseFactory mongoDbFactory, MongoConverter mongoConverter) {
}
1.3 添加配置
引入依赖之后,需要在配置文件中添加 MongoDB 的连接信息,如同使用 MySQL 一样需要给出它的连接信息。可以通过配置文件,定义其配置参数,具体参数有如下(将其对应参数写在 application.properties 或者 application.yml 即可):
参数 | 描述 |
---|---|
spring.data.mongodb.additional-hosts | 验证的数据库 |
spring.data.mongodb.authentication-database | 验证的数据库 |
spring.data.mongodb.auto-index-creation | 是否自动创建索引 |
spring.data.mongodb.database | 指定要使用的数据库名称,初始化数据的时候,会自动创建。 |
spring.data.mongodb.field-naming-strategy | 字段命名策略 |
spring.data.mongodb.gridfs.bucket | |
spring.data.mongodb.gridfs.database | |
spring.data.mongodb.host | 设置 MongoDB 主机名,默认为 localhost。 |
spring.data.mongodb.password | MongoDB数据库密码,根据实际情况填写即可 |
spring.data.mongodb.port | 设置 MongoDB 端口号,默认为 27017。 |
spring.data.mongodb.repositories.type | |
spring.data.mongodb.ssl.bundle | |
spring.data.mongodb.ssl.enabled | |
spring.data.mongodb.uri | 定义完整的 MongoDB URI 地址,通常优先于其他单独的属性 |
spring.data.mongodb.username | MongoDB数据库用户,根据实际情况填写即可 |
spring.data.mongodb.uuid-representation |
1.4 定义对应集合的实体类
操作 MySQL 时,我们会将 MySQL 的表在项目中定义一个对应的实体类,操作 MongoDB 的集合也需要定义一个对应的实体类,这里定义一个 SysUser 的实体类来进行操作。
java
@Data
@Builder
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class SysUser {
@Id
private String id;
@Field("name")
private String name;
private Integer age;
private String gender;
}
注解名称 | 作用对象 | 功能 |
---|---|---|
@Document | 实体类 | 表明这是一个 MongoDB 的文档集合,相当于 MySQL 的数据表,默认为实体类名称。 |
@CompoundIndex | 实体类 | 复合索引 |
@Id | 字段 | 用于实体类中的成员变量,表示主键标识,会将该字段与 MongoDB 生成的 _id 字段进行对应。 |
@Field | 字段 | 用于实体类中的成员变量,表示 MongoDB 文档集合中的字段,其值对应集合的字段名称。 |
@Indexed | 字段 | 声明该字段需要加索引,加索引后以该字段为条件检索将大大提高速度 |
@Transient | 字段 | 表示该字段不在 mongo 中存储,既忽略该字段 |
【注意】就个人而言,不太推荐使用 @Document 来定义实体类,由于 Mongo 的特性,在我们保存数据时,若是集合中没有某些字段,Mongo 会自动创建,而且处于业务需求,可能存在同样的数据结构、不同内容需要存放于不同的集合中,我们只需创建一个实体类,然后指定不同集合存储数据即可。
1.5 注入 MongoTemplate
MongoTemplate 基于 Spring 容器提供了一组对 MongoDB 操作的基本方法,只要将 MongoTemplate 注入到需要使用的类中,即可直接使用。通过 @Autowired 将 MongoTemplate 进行注入,如下所示:
java
@Resource
private MongoTemplate mongoTemplate;
二、核心对象
MongoDB 支持非常强大的查询功能,使用 Query 和 Criteria 对象,可以构建复杂的查询条件并执行查询。Criteria 是 MongoTemplate 的标准查询接口,它可以把多个查询条件通过链式操作进行拼接,然后通过 Query 可以构建查询语句。
2.1 Query
Query 表示条件、排序等的 MongoDB 查询对象,用来封装所有的查询条件。我们先看看 Query 的构造方法,如下所示:
java
public Query() {
}
/**
* 通过注入一个 CriteriaDefinition 条件对象获得 Query 查询对象
* 在简单查询时使用此方法将非常的方便
*/
public Query(CriteriaDefinition criteriaDefinition) {
this.addCriteria(criteriaDefinition);
}
Query 对象创建也很简单,如下所示:
java
// 用来封装所有条件的对象
Query query = new Query();
// 或者
Query query = new Query(criteria);
Query 类有一些额外的方法,可以为查询提供选项:
方法 | 简要说明 |
---|---|
Query addCriteria(CriteriaDefinition criteriaDefinition) | 用于向查询添加其他查询条件 |
Field fields() | 用于定义要包含在查询结果中的字段 |
Query skip(long skip) | 跳过文档的数量,可以与 limit 配合使用实现分页效果。 |
Query limit(int limit) | 用于限制将返回文档结果的数量(大小) |
Query with(Pageable pageable) | 添加一个分页对象 |
Query with(Sort sort) | 用于为结果提供排序定义 |
java
@Test
public void complexQuery() {
Query pageQuery=query.with(PageRequest.of(pageIndex - 1, pageSize)).with(Sort.by(Sort.Direction.DESC,"classNo"));
// 根据单个条件查询集合中的文档数据,并按指定字段进行排序与限制指定数目
Query query = new Query(Criteria.where("userName").is(userName)).with(Sort.by("createTime")).limit(2).skip(1);
}
2.2 Criteria
用于封装所有的查询条件对象,相当于 SQL 的 where。它遵循流畅的 API 风格,可以轻松地将多个条件链接在一起。我们先看看 Criteria 的构造方法,如下所示:
java
public Criteria() {}
public Criteria(String key) {}
protected Criteria(List<Criteria> criteriaChain, String key) {}
Criteria 类提供以下方法,所有这些方法都对应于 MongoDB 中的操作符:
方法 | Mongodb | 简要说明 |
---|---|---|
Criteria where(string key) | $expr | 静态方法,用它可以很方便的定义查询条件 |
Criteria and(String key) | $and | |
Criteria all(Object value) | 匹配所有指定元素的文档。 | |
Criteria exists(boolean value) | $exists | 查询存在指定字段的文档。 |
Criteria gt(Object value) | $gt | 范围查询,匹配大于(>)指定值的文档 |
Criteria gte(Object value) | $gte | 范围查询,匹配大于等于(>=)指定值的文档。 |
Criteria in(Object... values) | $in | 包含 |
Criteria is(Object value) | $is | 精确查询 |
Criteria isNull() | ||
Criteria isNullValue() | ||
Criteria lt(Object value) | $lt | 范围查询,匹配小于(<)指定值的文档。 |
Criteria lte(Object value) | $lte | 范围查询,匹配小于等于(<=)指定值的文档。 |
Criteria mod(Number value, Number remainder) | 取余条件查询。 | |
Criteria ne(Object value) | $ne | 匹配不等于(≠)指定值的文档。 |
Criteria nin(Object... values) | $nin | |
Criteria not(Object value) | $not | 查询与表达式不匹配的文档。 |
regex(String re) | $regex | 模糊条件。正则表达式,用于模式匹配 |
Criteria size(int size) | $size | 匹配数组长度为指定大小的文档。 |
Criteria andOperator(Criteria... criteria) | $and | 创建与操作 |
Criteria orOperator(Criteria... criteria) | $or | 创建或操作 |
Criteria norOperator(Criteria... criteria) | $nor |
java
@Test
public void complexQuery() {
/**
* 根据【AND】关联多个查询条件,查询集合中的文档数据
*/
Criteria nameCriteria = Criteria.where("name").is("成龙");
Criteria ageCriteria = Criteria.where("age").gte(30);
Criteria orOperatorCriteria = new Criteria().orOperator(nameCriteria, ageCriteria);
/**
* 根据【OR】关联多个查询条件,查询集合中的文档数据
*/
Criteria genderCriteria = Criteria.where("gender").is("女");
Criteria andOperatorCriteria = new Criteria().andOperator(genderCriteria);
Query query = new Query();
query.addCriteria(andOperatorCriteria);
query.addCriteria(orOperatorCriteria);
}
这里的写法类似于 SQL 中的 where ( name = "成龙" or age >= 30 ) and gender="女"
,总体来看,一个 Criteria 实例,就是一个查询条件。我们可以通过 or、and 操作来不断的组合生成一个新的Criteria实例,也就是一个新的查询条件 ,并且可以以此查询条件继续组合生成更高级的Criteria,以此不断的类推。
Criteria orOperatorCriteria andOperatorCriteria dname = 成龙 age >= 30 gender="女"
2.3 Update
用于轻松构建 MongoDB 更新子句的类,位于 org.springframework.data.mongodb.core.query
包中。其常用方法如下表所示:
方法 | 简要说明 |
---|---|
Update update(String key,Object value) | 更新字段 |
Update addToSet(String key) | 用来添加值到一个数组中去,如果数组中已经存在该值,那么将不会有任何的操作。 |
Update currentDate(String key) | 用来设置字段的值为当前时间 |
Update currentTimestamp(String key) | |
void inc(String key) | |
Update inc(String key, Number inc) | 用来对字段的值进行增加和减少指定的值 |
Update max(String key, Object value) | 用来判断字段的值是否比指定的值大,如果是,则将指定的值设置给字段。 |
Update min(String key, Object value) | 用来判断字段的值是否比指定的值小,如果是,则将指定的值设置给字段。 |
Update multiply(String key, Number multiplier) | 用来对字段的值乘以一个数字 |
Update pop(String key, Position pos) | 用来从字段数组中的头部和尾部删除一个元素 |
Update pull(String key, @Nullable Object value) | 用来从字段数组值中删除所有指定的值 |
Update pullAll(String key, Object[] values) | 用来从字段数组值中删除所有指定的值 |
Update push(String key, Object value) | 用来向已有的数组末尾加入一个元素。 要是不存在,就会创建一个新的。如果已存在,会造成元素的重复。所以在使用的时候,要确保该元素不存在。 |
Update rename(String oldName, String newName) | 用来对字段进行重命名 |
Update set(String key, Object value) | 将字段的值设置为指定的值,如果该字段不存在,将添加一个具有指定值的新字段。 |
Update setOnInsert(String key, Object value) | 设置字段值,字段不存在则新建字段 |
Update unset(String key) | 用来删除指定的字段。 |
三、集合操作
集合是 MongoDB 中存储文档的容器,类似于关系型数据库中的表。它是数据库中的一个逻辑分组,用于组织和管理相关的文档。一个数据库可以包含多个集合,每个集合可以包含零个或多个文档。集合中的文档可以具有不同的结构,即它们可以包含不同的字段和数据类型,这给 MongoDB 带来了极大的灵活性,但都遵循 MongoDB 的文档格式规范(BSON格式)。
3.1 新增操作
在 MongoDB 中,集合是不需要手动创建,当创建文档时,如果文档所在的集合不存在,就会自动创建集合。MongoDB 会在第一次插入文档时自动创建集合,但也可以显式创建集合,以便进行自定义配置,如下所示:
java
MongoCollection<Document> createCollection(Class entityClass);
MongoCollection<Document> createCollection(Class entityClass, CollectionOptions collectionOptions);
MongoCollection<Document> createCollection(String collectionName);
MongoCollection<Document> createCollection(String collectionName CollectionOptions collectionOptions);
CollectionOptions 指定了创建集合要用的一些参数:
java
public class CollectionOptions {
// 指定集合中的最大文档数量。当达到最大值,会自动删除最早存入的文档。
private Long maxDocuments;
// 指定整个集合的容量。当达到最大值,会将旧文档移除。
private Long size;
// 是否创建固定大小集合。当达到最大值时,会自动覆盖最早的文档。当该值为 true 时,必须指定 size 参数。
private Boolean capped;
// 用于文档验证的表达式
private Collation collation;
// 用来设置自定义规则,对集合中的文档进行验证。
private ValidationOptions validationOptions;
// 用来创建时序集合的
private TimeSeriesOptions timeSeriesOptions;
}
【注意】在 MongoDB 中,自动创建集合简单快速、适合快速原型开发,不需要事先定义集合结构。但可能会导致数据结构不一致(尤其在团队协作中),而且自动创建的集合无法预设索引或其他选项。特别说明一下,若插入的集合已经存在,则会抛出异常。
3.2 查询操作
方法 | 简要说明 |
---|---|
String getCollectionName(entityClass) | 可获取到entityClass实体类所对应的集合名称 |
MongoCollection<Document> getCollection(collectionName) | 返回的是基本的Driver集合对象,即DBCollection类型 |
Set<String> getCollectionNames() | 返回一个String列表,包含所有集合名称 |
boolean collectionExists(entityClass) boolean collectionExists(String collectionName) | 判断集合存在 |
3.3 删除操作
删除集合是另一项常见的操作,MongoDB 提供了简单的命令来执行此操作。删除集合将删除集合中的所有文档,并释放相关资源。
方法 | 简要说明 |
---|---|
dropCollection(entityClass) | 删除集合 |
dropCollection(collectionName) |
【注意】一旦集合被删除,所有文档将无法恢复。务必谨慎操作,尤其是在生产环境中,确保有足够的权限进行集合的创建和删除操作。通常,只有管理员用户或具有特定权限的用户才能执行这些操作。
四、文档的 CRUD 操作
文档是 MongoDB 中的最小数据单元,以键值对的形式组织,类似于 JSON 对象(实际上是 BSON,即 Binary JSON)。MongoTemplate 提供了一系列方便的方法来执行基本的 CRUD 操作。CRUD 是 MongoDB 中的核心操作,包含插入、读取、更新和删除等,以下将逐一讲解这些操作。
4.1 保存(插入)操作
MongoTemplate 上有几个便捷方法,如下表所示,用于保存和插入对象。Mongodb 中也像传统的关系数据库里表一样,有主键(_id)概念,用来唯一标识。当用户往 Mongodb 中插入一条新记录的时候,如果没有指定_id属性,那么 mongodb 会自动生成一个 ObjectId 类型的值,保存为 _id 的值。
方法 | 简要说明 |
---|---|
insert(T objectToSave) insert(T objectToSave, String collectionName) | |
insert(Class domainType) insert(Collection batchToSave, Class entityClass) insert(Collection batchToSave, String collectionName) | 文档插入。 若新增数据的主键已经存在,则会抛出异常提示主键重复,不保存当前数据。 |
insertAll(Collection batchToSave) | 批量插入多个文档,批量插入不用遍历,效率高 |
save(T objectToSave) save(T objectToSave, String collectionName) | 用于保存或更新操作,传递定义好的JavaBean即可,被保存的数据对象会作为返回值被返回。 通过主键 ID 进行判断,如果存在就更新,否则就插入。 |
【注意】没指定集合名称时,会取 @Document注解中的集合名称。
java
@SpringBootTest
public class SaveTest {
@Resource
private MongoTemplate mongoTemplate;
private final String collectionName = "SaveTest";
@BeforeEach
public void init() {
// 删除集合
mongoTemplate.dropCollection(collectionName);
}
/**
* 自定义集合,插入文档
*/
@Test
public void insertTest() {
SysUser sysUser = new SysUser("12", "黄小飞", "女", 33);
mongoTemplate.insert(sysUser, collectionName);
}
/**
* 自定义集合,批量插入文档
*/
@Test
public void insertBatchTest() {
List<SysUser> userList = new ArrayList<>();
userList.add(new SysUser("1", "白鹿", "女", 31));
userList.add(new SysUser("2", "陈都灵", "女", 32));
userList.add(new SysUser("3", "高圆圆", "女", 46));
userList.add(new SysUser("4", "张含韵", "女", 36));
userList.add(new SysUser("5", "李沁", "女", 35));
userList.add(new SysUser("6", "胡歌", "男", 43));
userList.add(new SysUser("7", "刘亦菲", "女", 38));
userList.add(new SysUser("8", "成龙", "男", 71));
userList.add(new SysUser("9", "杨幂", "男", 39));
userList.add(new SysUser("10", "陈钰琪", "女", 33));
mongoTemplate.insert(userList, collectionName);
}
/**
* 自定义集合,存储文档,如果没有插入,否则更
*/
@Test
public void saveTest() {
SysUser sysUser = new SysUser("12", "黄小飞", "女", 33);
mongoTemplate.save(sysUser, collectionName);
}
}
【注意】使用 insert 插入文档时,如果插入数据的主键已经存在,则会抛键重复异常,不保存当前数据。而使用 save 插入文档时,如果插入数据的主键已经存在,则会更新当前数据,如果不存在则会保存当前数据。
4.2 查询操作
MongoDB 提供了灵活的查询语法,支持条件查询、复杂查询、聚合查询等。
方法 | 简要说明 |
---|---|
List find(query, entityClass) List find(query, entityClass, collectionName) | 根据查询条件查询多个文档 |
findOne(query, entityClass) findOne(query, entityClass, collectionName) | 用于查找集合中的单个文档。如果找到多个匹配的文档,它只返回第一个。 |
findById(id, entityClass) findById(id, entityClass, collectionName) | 根据ID查询文档。在添加数据时, MongoDB 会自动生成了 id,名为 _id 。 |
List findAll(className) List findAll(className, collectionName) | 查询指定集合中所有数据 |
count(query, entityClass) count (query, collectionName) count(query, entityClass, collectionName) | 查询符合条件的数量 |
findDistinct(query, field, entityClass, resultClass) findDistinct(query, field, collectionName, entityClass, resultClass) | 只能用于单个字段去重查询的方法,主要用于获取某个字段的所有不同值。 |
【注意】没指定集合名称时,会取 @Document注解中的集合名称。
java
@SpringBootTest
public class FindTest {
@Resource
private MongoTemplate mongoTemplate;
private final String collectionName = "FindTest";
@BeforeEach
public void init() {
// 删除集合
mongoTemplate.dropCollection(collectionName);
List<SysUser> userList = new ArrayList<>();
userList.add(new SysUser("1", "白鹿", "女", 31));
userList.add(new SysUser("2", "陈都灵", "女", 32));
userList.add(new SysUser("3", "高圆圆", "女", 46));
userList.add(new SysUser("4", "张含韵", "女", 36));
userList.add(new SysUser("5", "李沁", "女", 35));
userList.add(new SysUser("6", "胡歌", "男", 43));
userList.add(new SysUser("7", "刘亦菲", "女", 38));
userList.add(new SysUser("8", "成龙", "男", 71));
userList.add(new SysUser("9", "杨幂", "男", 39));
userList.add(new SysUser("10", "陈钰琪", "女", 33));
mongoTemplate.insert(userList, collectionName);
}
/**
* 根据条件查询集合中符合条件的文档
*/
@Test
public void findTest() {
Query query = new Query(Criteria.where("age").gte(30).lte(40));
mongoTemplate.find(query, SysUser.class, collectionName).forEach(System.out::println);
}
/**
* 根据条件查询集合中符合条件的文档,返回第一条数据
*/
@Test
public void findOneTest() {
Query query = new Query(Criteria.where("gender").is("女"));
SysUser sysUser = mongoTemplate.findOne(query, SysUser.class, collectionName);
System.out.println("查询结果:" + sysUser);
}
/**
* 查询集合中指定的ID文档数据
*/
@Test
public void findByIdTest() {
SysUser sysUser = mongoTemplate.findById("1", SysUser.class, collectionName);
System.out.println(sysUser);
}
/**
* 查询集合中的全部文档数据
*/
@Test
public void findAllTest() {
mongoTemplate.findAll(SysUser.class, collectionName).forEach(System.out::println);
}
@Test
public void countTest() {
System.out.println( mongoTemplate.count(new Query(), collectionName));
}
}
4.3 更新操作
4.3.1 基本更新操作
在 MongoDB 中,更新文档的操作包括单文档更新和多文档更新,可以使用多种方法实现,常用的方法如下表所示。
方法 | 简要说明 |
---|---|
UpdateResult updateFirst(query, update, entityClass) UpdateResult updateFirst (query, update, collectionName) UpdateResult updateFirst(query, update, entityClass, collectionName) | 用于更新第一个匹配查询条件的文档 |
UpdateResult updateMulti(query, update, entityClass) UpdateResult updateMulti (query, update, collectionName) UpdateResult updateMulti(query, update, entityClass, collectionName) | 用于更新所有匹配查询条件的文档 |
UpdateResult upsert(query, update, entityClass) UpdateResult upsert (query, update, collectionName) UpdateResult upsert(query, update, entityClass, collectionName) | 进行插入或更新操作。如果文档不存在,则插入新文档,否则更新文档。 这种操作非常符合我们某些需要保证在一定条件下只能有一个文档的情况。 |
【注意】没指定集合名称时,会取 @Document注解中的集合名称。
java
@SpringBootTest
public class UpdateTest {
@Resource
private MongoTemplate mongoTemplate;
private final String collectionName = "UpdateTest";
@BeforeEach
void init() {
mongoTemplate.dropCollection(collectionName);
List<SysUser> sysUserList = new ArrayList<>();
sysUserList.add(SysUser.builder().id("ID10001").name("Tom").age(34).gender("男").build());
sysUserList.add(SysUser.builder().id("ID10002").name("Tony").age(23).gender("男").build());
sysUserList.add(SysUser.builder().id("ID10003").name("Ross").age(44).gender("女").build());
sysUserList.add(SysUser.builder().id("ID10004").name("Gloria").age(14).gender("女").build());
sysUserList.add(SysUser.builder().id("ID10005").name("Linda").age(24).gender("女").build());
sysUserList.add(SysUser.builder().id("ID10006").name("regina").age(26).gender("女").build());
sysUserList.add(SysUser.builder().id("ID10007").name("John").age(22).gender("男").build());
sysUserList.add(SysUser.builder().id("ID10008").name("Michael").age(22).gender("男").build());
mongoTemplate.save(sysUserList, collectionName);
}
/**
* 更新文档,匹配查询到的文档数据中的第一条数据
*/
@Test
public void updateFirstTest() {
// 更新条件
Query query = new Query(Criteria.where("_id").is("ID10001"));
System.out.println("更新前" + mongoTemplate.find(query, SysUser.class,collectionName));
Update update = new Update();
// 更新值
update.set("name", "张三");
update.set("sex", "男");
// 更新查询满足条件的文档数据(第一条)
UpdateResult updateResult = mongoTemplate.updateFirst(query, update, SysUser.class, collectionName);
System.out.println(updateResult);
}
/**
* 更新文档,匹配查询到的文档数据中的所有数据
*/
@Test
public void updateMultiTest() {
// 更新条件
Query query = new Query(Criteria.where("age").gte(30));
// 更新值
Update update = Update.update("age", 33);
// 更新查询满足条件的文档数据(全部)
mongoTemplate.updateMulti(query, update, SysUser.class, collectionName);
}
@Test
public void upsertTest() {
Query query = new Query(Criteria.where("age").gte(60));
Update update = Update.update("age", -1);
mongoTemplate.upsert(query, update, SysUser.class, collectionName);
}
}
4.3.2 查找并更新
修改数据时首先对数据进行查询,然后设置需要修改的值,进行数据的更新,如下表所示,可以选择返回更新前或更新后的文档。
方法 | 简要说明 |
---|---|
findAndModify(query, update, entityClass) findAndModify(query, update, collectionName) | 更新相匹配的文档,并返回旧的的文档。 |
findAndModify(query, update, options, entityClass); findAndModify(query, update, options, entityClass, collectionName); | 更新相匹配的文档,并返回旧的或新更新的文档。 |
【注意】没指定集合名称时,会取 @Document注解中的集合名称。
java
@SpringBootTest
public class UpdateTest {
@Resource
private MongoTemplate mongoTemplate;
private final String collectionName = "UpdateTest";
@BeforeEach
void init() {
mongoTemplate.dropCollection(collectionName);
List<SysUser> sysUserList = new ArrayList<>();
sysUserList.add(SysUser.builder().id("ID10001").name("Tom").age(34).gender("男").build());
sysUserList.add(SysUser.builder().id("ID10002").name("Tony").age(23).gender("男").build());
sysUserList.add(SysUser.builder().id("ID10003").name("Ross").age(44).gender("女").build());
sysUserList.add(SysUser.builder().id("ID10004").name("Gloria").age(14).gender("女").build());
sysUserList.add(SysUser.builder().id("ID10005").name("Linda").age(24).gender("女").build());
sysUserList.add(SysUser.builder().id("ID10006").name("regina").age(26).gender("女").build());
sysUserList.add(SysUser.builder().id("ID10007").name("John").age(22).gender("男").build());
sysUserList.add(SysUser.builder().id("ID10008").name("Michael").age(22).gender("男").build());
mongoTemplate.save(sysUserList, collectionName);
}
@Test
public void findAndModifyTest() {
Query query = new Query(Criteria.where("_id").is("ID10001"));
Update update = Update.update("name", "张三");
mongoTemplate.findAndModify(query, update, SysUser.class, collectionName);
}
}
4.4 删除操作
基本删除操作
删除操作同样通过 Query 类构造要删除的条件,然后调用 remove 方法进行删除即可。
方法 | 简要说明 |
---|---|
DeleteResult remove(Object object) DeleteResult remove(Object object, String collectionName) | 用于删除数据,一般都是传递一个主键ID即可。 |
DeleteResult remove(query, entityClass) DeleteResult remove (query, collectionName) DeleteResult remove(query, entityClass, collectionName) | 用于删除符合条件的文档 |
【注意】没指定集合名称时,会取 @Document注解中的集合名称。
java
@SpringBootTest
public class RemoveTest {
@Resource
private MongoTemplate mongoTemplate;
private final String collectionName = "RemoveTest";
@BeforeEach
public void init() {
// 删除集合
mongoTemplate.dropCollection(collectionName);
List<SysUser> userList = new ArrayList<>();
userList.add(new SysUser("1", "白鹿", "女", 31));
userList.add(new SysUser("2", "陈都灵", "女", 32));
userList.add(new SysUser("3", "高圆圆", "女", 46));
userList.add(new SysUser("4", "张含韵", "女", 36));
userList.add(new SysUser("5", "李沁", "女", 35));
userList.add(new SysUser("6", "胡歌", "男", 43));
userList.add(new SysUser("7", "刘亦菲", "女", 38));
userList.add(new SysUser("8", "成龙", "男", 71));
userList.add(new SysUser("9", "杨幂", "男", 39));
userList.add(new SysUser("10", "陈钰琪", "女", 33));
mongoTemplate.insert(userList, collectionName);
}
@Test
public void removeOne() {
Query query = new Query(Criteria.where("id").is("1"));
SysUser sysUser = mongoTemplate.findOne(query, SysUser.class, collectionName);
if (null != sysUser) {
mongoTemplate.remove(sysUser, collectionName);
}
long count = mongoTemplate.count(query, collectionName);
System.out.println("count = " + count);
}
@Test
public void removeAll() {
Query query = new Query(Criteria.where("age").gte(30));
long count = mongoTemplate.count(query, collectionName);
System.out.println("删除前,count=" + count);
// 删除所有匹配的文档
mongoTemplate.remove(query, collectionName);
count = mongoTemplate.count(query, collectionName);
System.out.println("删除后,count=" + count);
}
@Test
public void removeLimit() {
Query query = new Query(Criteria.where("age").gte(30));
long count = mongoTemplate.count(query, collectionName);
System.out.println("删除前,count=" + count);
// 删除前两个文档
mongoTemplate.remove(query.limit(2), collectionName);
count = mongoTemplate.count(query, collectionName);
System.out.println("删除后,count=" + count);
}
}
查找并删除
方法 | 简要说明 |
---|---|
findAndRemove(query, entityClass) findAndRemove(query, collectionName) | 用于查找并删除单个文档,并可以选择返回删除的文档。如果找不到匹配的文档,则返回 null。 |
findAllAndRemove (query, collectionName) findAllAndRemove(query, entityClass) findAllAndRemove(query, entityClass, collectionName) | 查询出符合条件的所有结果,并将符合条件的所有数据删除。 |
【注意】没指定集合名称时,会取 @Document注解中的集合名称。
java
@SpringBootTest
public class RemoveTest {
@Resource
private MongoTemplate mongoTemplate;
private final String collectionName = "RemoveTest";
@BeforeEach
public void init() {
// 删除集合
mongoTemplate.dropCollection(collectionName);
List<SysUser> userList = new ArrayList<>();
userList.add(new SysUser("1", "白鹿", "女", 31));
userList.add(new SysUser("2", "陈都灵", "女", 32));
userList.add(new SysUser("3", "高圆圆", "女", 46));
userList.add(new SysUser("4", "张含韵", "女", 36));
userList.add(new SysUser("5", "李沁", "女", 35));
userList.add(new SysUser("6", "胡歌", "男", 43));
userList.add(new SysUser("7", "刘亦菲", "女", 38));
userList.add(new SysUser("8", "成龙", "男", 71));
userList.add(new SysUser("9", "杨幂", "男", 39));
userList.add(new SysUser("10", "陈钰琪", "女", 33));
mongoTemplate.insert(userList, collectionName);
}
/**
* 删除符合条件的单个文档,并返回删除的文档
*/
@Test
public void findAndRemoveTest() {
Query query = new Query(Criteria.where("id").is(2));
SysUser sysUser = mongoTemplate.findAndRemove(query, SysUser.class);
System.out.println("删除的文档数据:" + sysUser.toString());
}
/**
* 删除符合条件的所有文档,并返回删除的文档
*/
@Test
public void findAllAndRemoveTest() {
Query query = new Query(Criteria.where("age").gte(30));
long count = mongoTemplate.count(query, collectionName);
System.out.println("删除前,count=" + count);
// 删除所有匹配的文档
List<SysUser> sysUserList = mongoTemplate.findAllAndRemove(query, collectionName);
System.out.println("删除的数据:" + Arrays.toString(sysUserList.toArray()));
count = mongoTemplate.count(query, collectionName);
System.out.println("删除后,count=" + count);
}
@Test
public void findAllAndRemoveLimit() {
Query query = new Query(Criteria.where("age").gte(30));
long count = mongoTemplate.count(query, collectionName);
System.out.println("删除前,count=" + count);
// 删除前两个文档
List<SysUser> sysUserList = mongoTemplate.findAllAndRemove(query.limit(2), collectionName);
System.out.println("删除的数据:" + Arrays.toString(sysUserList.toArray()));
count = mongoTemplate.count(query, collectionName);
System.out.println("删除后,count=" + count);
}
}
五、知识拓展
5.1 查询指定字段的值
在 MongoDB 中,文档是以键值对的形式存储的,每个文档可以包含多个字段,每个字段由一个键和一个值组成。在查询文档时,有时只需要获取文档中的部分字段,而不是全部字段,MongoTemplate 提供了一种简单的方式来查询指定字段的值。
-
查询单个字段的值 :要查询单个字段的值,可以使用
findOne
方法,以下是查询单个字段的值的示例代码:javaQuery query = new Query(); query.addCriteria(Criteria.where("name").is("John")); String fieldValue = mongoTemplate.findOne(query, String.class, "users"); System.out.println(fieldValue);
在上面的示例中,创建了一个 Query 对象,并通过 Criteria 来指定查询条件。然后调用 findOne 方法传入查询条件、返回值类型和集合名,它会返回符合条件的第一个文档,并将指定字段的值转换为指定的返回值类型。
-
查询指定字段的值 :要查询指定字段的值,可以使用
fields
方法来指定要返回的字段,以下是查询指定字段的值的示例代码:javaQuery query = new Query(); query.addCriteria(Criteria.where("age").gte(18)); query.fields().include("name").exclude("age"); List<User> users = mongoTemplate.find(query, User.class, "users"); for (User user : users) { System.out.println(user.getName()); }
在上面的示例中,使用 fields 方法来指定要返回的字段。在 include 方法中,指定要返回的字段名。在 exclude 方法中,指定要排除的字段名。这样,查询结果中只会包含指定的字段。
5.2 结果类
DeleteResult
此类包含有关已执行删除操作的信息,如下表所示。
方法 | 简要说明 |
---|---|
long getDeletedCount() | 返回已删除的文档数。 |
boolean wasAcknowledged() | 返回写入是否已确认。 |
UpdateResult
此类包含有关已执行更新或替换操作的信息,如下表所示。
方法 | 简要说明 |
---|---|
long getMatchedCount() | 返回匹配的文档数。 |
long getModifiedCount() | 返回已修改文档的数量。 |
BsonValue getUpsertedId() | 如果执行的是一个upsert操作(即先尝试更新,如果没有找到匹配的文档则插入),则返回新插入文档的ID。 如果没有进行upsert操作或者没有插入任何文档,则返回null。 |
boolean isModifiedCountAvailable() |
六、小结
MongoDB 已经被越来越多的使用,它适合于对大量的、无固定数据结构的数据进行存储,本文简单的介绍了通过使用 MongoTemplate 来对 MongoDB 进行 CRUD 的操作。MongoTemplate 提供了一个灵活而强大的方式来操作 MongoDB 数据库,非常适合在 Spring 应用中使用。我们可以根据自己的需求,进一步扩展和优化这些基础操作。
