MongoCollection 上的 findAndModify(...) 方法可以更新一个文档,并在一次操作中返回旧的或新更新的文档。
MongoTemplate 提供了四个 findAndModify() 方法的重载,这些方法参数采用查询(Query)和更新(Update)类,并将文档转换为你的 POJO。
findAndModify() 方法定义如下:
// 更新文档,使用默认集合名,且返回旧对象 <T> T findAndModify(Query query, Update update, Class<T> entityClass); // 更新文档,使用指定的集合名,且返回旧对象 <T> T findAndModify(Query query, Update update, Class<T> entityClass, String collectionName); // 更新文档,通过 FindAndModifyOptions 选项指定返回旧的还是新的文档,使用默认集合名 <T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass); // 更新文档,通过 FindAndModifyOptions 选项指定返回旧的还是新的文档,使用指定的集合名 <T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass, String collectionName);
以下示例将几个 Person 对象插入容器中并执行 findAndUpdate() 操作:
(1)Person 定义
package com.hxstrive.springdata.mongodb.entity;
import lombok.Builder;
import lombok.Data;
import lombok.ToString;
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.mongodb.core.mapping.Document;
/**
* 用户
* @author hxstrive.com
*/
@Document("my_person")
@TypeAlias("pers")
@Data
@Builder
@ToString
public class Person extends Contact {
/** ID,自动映射到 MongoDB 的 _id 字段 */
private String id;
/** 姓名 */
private String name;
/** 年龄 */
private int age;
}(2)客户端代码
package com.hxstrive.springdata.mongodb;
import com.hxstrive.springdata.mongodb.entity.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
@SpringBootTest
class FindAndModifyTest {
@Autowired
private MongoTemplate mongoTemplate;
@Test
void contextLoads() {
// 删除集合
mongoTemplate.dropCollection(Person.class);
// 准备数据
mongoTemplate.insert(Person.builder().name("Joe").age(28).build());
mongoTemplate.insert(Person.builder().name("Tom").age(30).build());
mongoTemplate.insert(Person.builder().name("Helen").age(41).build());
// 查询条件和更新对象
Query query = new Query(Criteria.where("name").is("Joe"));
Update update = new Update().inc("age", 40);
// 1.修改对象,返回旧对象
Person oldValue = mongoTemplate.update(Person.class)
.matching(query)
.apply(update)
.findAndModifyValue(); // 返回旧的 person 对象
System.out.println("旧Person name=" + oldValue.getName() + " age=" + oldValue.getAge());
// 查询刚刚修改的最新对象
Person newValue = mongoTemplate.query(Person.class)
.matching(query)
.firstValue();
System.out.println("新Person name=" + newValue.getName() + " age=" + newValue.getAge());
// 2.修改文档,返回新文档对象
Person newestValue = mongoTemplate.update(Person.class)
.matching(query)
.apply(update)
// 现在,在更新时返回新的文档
.withOptions(FindAndModifyOptions.options().returnNew(true))
.findAndModifyValue();
System.out.println("新Person name=" + newestValue.getName() + " age=" + newestValue.getAge());
// 3.修改文档,使用多个参数的 findAndModify 方法
newestValue = mongoTemplate.findAndModify(query, update,
FindAndModifyOptions.options().returnNew(true), Person.class);
System.out.println("新Person name=" + newestValue.getName() + " age=" + newestValue.getAge());
}
}运行代码,输出结果:
旧Person name=Joe age=28 新Person name=Joe age=68 新Person name=Joe age=108 新Person name=Joe age=148
FindAndModifyOptions 的方法能让你设置 returnNew、upsert 和 remove 选项。下面是一个从前面的代码片断延伸出来的例子:
package com.hxstrive.springdata.mongodb;
import com.hxstrive.springdata.mongodb.entity.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
@SpringBootTest
class FindAndModifyTest2 {
@Autowired
private MongoTemplate mongoTemplate;
@Test
void contextLoads() {
// 删除集合
mongoTemplate.dropCollection(Person.class);
// 准备数据
mongoTemplate.insert(Person.builder().name("Joe").age(28).build());
mongoTemplate.insert(Person.builder().name("Tom").age(30).build());
mongoTemplate.insert(Person.builder().name("Helen").age(41).build());
// 查询条件和更新对象
Query query = new Query(Criteria.where("name").is("Bill"));
Update update = new Update().inc("age", 40);
// 修改对象
// 返回新对象
// 如果查询条件匹配到文档,则执行修改动作。
// 如果查询条件未匹配到文档,则执行插入操作(文档内容=查询+更新)。
Person upserted = mongoTemplate.update(Person.class)
.matching(query)
.apply(update)
.withOptions(FindAndModifyOptions.options().upsert(true).returnNew(true))
.findAndModifyValue();
System.out.println("Person name=" + upserted.getName() + " age=" + upserted.getAge());
}
}执行完成后,效果如下图:
