Spring Data MongoDB 教程

更新集合中的文档

前面章节介绍了如何保存/插入对象到 MongoDB 中,本章节将介绍怎样去更新已经存在的文档。

Spring Data MongoDB 中,对于更新,你可以通过使用 MongoOperation.updateFirst() 来更新找到的第一个文档,或者你可以通过使用 MongoOperation.updateMulti() 方法来更新所有找到的符合查询条件的文档。

下面的例子显示了对所有储蓄账户的更新,我们通过使用 $inc 操作符在余额中添加一次性的 50 美元奖金:

import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Query;
import static org.springframework.data.mongodb.core.query.Update;

...

WriteResult wr = mongoTemplate.updateMulti(
   new Query(where("accounts.accountType").is(Account.Type.SAVINGS)),
   new Update().inc("accounts.$.balance", 50.00), Account.class);

除了前面讨论的查询之外,我们还通过使用 Update 对象来提供更新定义,即我们的更新条件。org.springframework.data.mongodb.core.query.Update 类拥有与 MongoDB 可用的更新修改器相匹配的方法。

它的大多数方法都返回 Update 对象,以便为 API 提供一种链式调用的风格(如:new Update().inc("age", 10).set("name", "Tom"))。

运行文档更新方法

  • updateFirst() 用更新后的文档更新第一个符合查询文档标准的文档。

  • updateMulti() 用更新后的文档更新所有符合查询文档条件的对象。

注意:updateFirst() 不支持排序,请使用 findAndModify() 应用排序。

Update类中的方法

你可以在 Update 类中使用一点 “语法糖”,因为它的方法是被链接在一起的。另外,你可以通过使用 public static Update update(String key, Object value) 方法和静态导入来创建一个新的 Update 实例。

Update 类包含以下方法:

  • Update addToSet(String key, Object value) 用来添加值到一个数组中去,如果数组中已经存在该值那么将不会有任何的操作。即使用 $addToSet 修饰符。

  • Update currentDate(String key) 用来设置字段的值为当前时间,值为 Date 类型或者 Timestamp 时间戳类型,默认是 Date 类型。即使用 $currentDate 修饰符,$currentDate操作符是只用在 update 操作上,不可以用在 insert 操作上。

  • Update currentTimestamp(String key) 使用 $currentDate 更新修饰符和 $type timeestamp 更新

  • Update inc(String key, Number inc) 用来对字段的值进行增加和减少指定的值,即使用 $inc 修饰符。

  • Update max(String key, Object max) 用来判断字段的值是否比指定的值小,如果是,则将指定的值设置给字段。即使用 $max 修饰符,取字段值和指定值两者间最大的值。

  • Update min(String key, Object min) 用来判断字段的值是否比指定的值大,如果是,则将指定的值设置给字段。即使用 $min 修饰符,取字段值和指定值两者间最小的值。

  • Update multiply(String key, Number multiplier) 用来对字段的值乘以一个数字,即使用 $mul 修饰符。

  • Update pop(String key, Update.Position pos) 用来从字段数组中的头部和尾部删除一个元素,即使用 $pop 修饰符。

  • Update pull(String key, Object value) 用来从字段数组值中删除所有指定的值,即使用 $pull 修饰符。

  • Update pullAll(String key, Object[] values) 用来从字段数组值中删除所有指定的值,即使用 $pullAll 修饰符。

  • Update push(String key, Object value) 用来向已有的数组末尾加入一个元素,要是元素不存在,就会创建一个新的元素。如果元素已存在,就会再添加一个一模一样的元素,会造成元素的重复。所以在使用的时候,要确保该元素不存在。即使用 $push 修饰符。

  • Update rename(String oldName, String newName) 用来对字段进行重命名,即使用 $rename 修饰符。

  • Update set(String key, Object value) 使用 $set 更新修改器来更新,$set 操作符将字段的值设置为指定的值,如果该字段不存在,$set 将添加一个具有指定值的新字段。

  • Update setOnInsert(String key, Object value) 如果 upsert 设为 true。当满足查询条件的记录存在,则不执行 $setOnInsert 中的操作,当满足条件的记录不存在则执行$setOnInsert 操作。与 $set 指令配合使用,可以作为 $set 指令的补充。当满足查询条件的记录存在,则执行 $set 操作,当满足查询条件的记录不存在,则新增一条记录。即使用 $setOnInsert 修饰符。

  • Update unset(String key) 用来删除指定的字段,即使用 $unset 修饰符。

一些更新修饰符,如 $push 和 $addToSet,允许嵌套其他运算符。

// { $push : { "category" : { "$each" : [ "spring" , "data" ] } } }
new Update().push("category").each("spring", "data")

// { $push : { "key" : { "$position" : 0 , "$each" : [ "Arya" , "Arry" , "Weasel" ] } } }
new Update().push("key").atPosition(Position.FIRST).each(Arrays.asList("Arya", "Arry", "Weasel"));

// { $push : { "key" : { "$slice" : 5 , "$each" : [ "Arya" , "Arry" , "Weasel" ] } } }
new Update().push("key").slice(5).each(Arrays.asList("Arya", "Arry", "Weasel"));

// { $addToSet : { "values" : { "$each" : [ "spring" , "data" , "mongodb" ] } } }
new Update().addToSet("values").each("spring", "data", "mongodb");

示例

(1)Student 实体代码

package com.hxstrive.springdata.mongodb.entity;

import lombok.Builder;
import lombok.Data;
import lombok.ToString;

import java.sql.Timestamp;
import java.util.Date;
import java.util.List;

/**
 * 学生
 * @author hxstrive.com
 */
@Data
@Builder
@ToString
public class Student {
    /** ID,自动映射到 MongoDB 的 _id 字段 */
    private String id;
    /** 姓名 */
    private String name;
    /** 年龄 */
    private int age;
    /** 学号 */
    private int studentId;
    /** 成绩 */
    private float score;
    /** 排名 */
    private int ranking;
    /** 兴趣爱好 */
    private List<String> interestList;
    /** 入学日期 */
    private Date startSchoolDate;
    private Timestamp timestamp;
}

(2)客户端代码

package com.hxstrive.springdata.mongodb;

import com.hxstrive.springdata.mongodb.entity.Person;
import com.hxstrive.springdata.mongodb.entity.Student;
import org.junit.jupiter.api.BeforeEach;
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.MongoTemplate;
import org.springframework.data.mongodb.core.query.Update;
import java.util.Collections;
import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Query.query;

@SpringBootTest
public class UpdateTest2 {

   @Autowired
   private MongoTemplate mongoTemplate;

   @BeforeEach
   public void init() {
       // 删除集合
       mongoTemplate.dropCollection(Person.class);

       Student s = Student.builder().id("ID10000").name("Tom").age(34)
               .studentId(1000).score(634.5f).ranking(10)
               .interestList(Collections.singletonList("basketball"))
               .build();

       // 将对象插入到数据库中
       mongoTemplate.save(s);
       System.out.println("Save: " + s);
   }

   @Test
   public void set() {
       // 将 id 为 ID10000 的学生的名字和成绩分别修改为 Helen 和 610
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().set("name", "Helen").set("score", 610), Student.class);
   }

   @Test
   public void addToSet() {
       // 向 id 为 ID10000 的学生的兴趣中添加 “football”
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().addToSet("interestList", "football"), Student.class);
   }

   @Test
   public void currentDate() {
       // 将 id 为 ID10000 的学生的入学时间设置为当前日期
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().currentDate("startSchoolDate"), Student.class);
   }

   @Test
   public void inc() {
       // 将 id 为 ID10000 的学生的成绩添加 5.5 分
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().inc("score", 5.5), Student.class);
   }

   @Test
   public void max() {
       // 如果 id 为 ID10000 的学生的成绩小于 650,则将 650 设置为他的新成绩
       // 即 score = max(634.5, 650)
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().max("score", 650), Student.class);
   }

   @Test
   public void min() {
       // 如果 id 为 ID10000 的学生的成绩大于 600,则将 600 设置为他的新成绩
       // 即 score = min(634.5, 600)
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().min("score", 600), Student.class);
   }

   @Test
   public void multiply() {
       // 将 id 为 ID10000 的学生成绩乘以 2
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().multiply("score", 2), Student.class);
   }

   @Test
   public void rename() {
       // rename()
       // 将 id 为 ID10000 的学生的 score 字段名称改为 new-score
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().rename("score", "new-score"), Student.class);
   }

   @Test
   public void unset() {
       // 将 id 为 ID10000 的学生的 score 字段删除
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().unset("score"), Student.class);
   }

   @Test
   public void push() {
       // 向 id 为 ID10000 的学生的兴趣中添加 football,football
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().push("interestList", "football"), Student.class);
   }

   @Test
   public void popFirst() {
       // 向 id 为 ID10000 的学生的兴趣中添加 football
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().push("interestList", "football"), Student.class);

       // 从 id 为 ID10000 的学生的兴趣的头部删除一个元素
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().pop("interestList", Update.Position.FIRST), Student.class);
   }

   @Test
   public void popLast() {
       // 向 id 为 ID10000 的学生的兴趣中添加 football
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().push("interestList", "football"), Student.class);

       // 从 id 为 ID10000 的学生的兴趣的尾部删除一个元素
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().pop("interestList", Update.Position.LAST), Student.class);
   }

   @Test
   public void pull() {
       // 向 id 为 ID10000 的学生的兴趣中添加 football,football
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().push("interestList", "football"), Student.class);
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().push("interestList", "football"), Student.class);

       // 删除 id 为 ID10000 的学生的兴趣中所有 “football”
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().pull("interestList", "football"), Student.class);
   }

   @Test
   public void pullAll() {
       // 向 id 为 ID10000 的学生的兴趣中添加 football,football
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().push("interestList", "football"), Student.class);
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().push("interestList", "football"), Student.class);

       // 从 id 为 ID10000 的学生的兴趣中删除所有的 “basketball” 和 “football”
       mongoTemplate.updateMulti(query(where("id").is("ID10000")),
               new Update().pullAll("interestList", new Object[]{"basketball", "football"}), Student.class);
   }

   @Test
   public void setOnInsert() {
       // 由于 id 为 ID10000 的学生已经存在,不修改 score 为 590
       mongoTemplate.upsert(query(where("id").is("ID10000")),
               new Update().setOnInsert("score", 590), Student.class);
       // 由于 id 为 ID20000 的学生已经不存在,新增一条记录,score 为 590
       mongoTemplate.upsert(query(where("id").is("ID20000")),
               new Update().setOnInsert("score", 590), Student.class);
   }

}
说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号