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()); } }
执行完成后,效果如下图: