MongoTemplate / ReactiveMongoTemplatge允许您保存、更新和删除域对象,并将这些对象映射到存储在 MongoDB 中的文档。 命令式 API 和反应式 API 的 API 签名基本相同,只是返回类型不同。 同步 API 使用 ,单个和响应式对应物由 、 和 组成。voidObjectListMono<Void>Mono<Object>FluxSpring中文文档

请考虑以下类:Spring中文文档

public class Person {

	private String id;
	private String name;
	private int age;

	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public String getId() {
		return id;
	}

	public String getName() {
		return name;
	}

	public int getAge() {
		return age;
	}

	@Override
	public String toString() {
		return "Person [id=" + id + ", name=" + name + ", age=" + age + "]";
	}
}

给定前面示例中的类,您可以保存、更新和删除对象,如以下示例所示:PersonSpring中文文档

public class MongoApplication {

  private static final Log log = LogFactory.getLog(MongoApplication.class);

  public static void main(String[] args) {

    MongoOperations template = new MongoTemplate(new SimpleMongoClientDbFactory(MongoClients.create(), "database"));

    Person p = new Person("Joe", 34);

    // Insert is used to initially store the object into the database.
    template.insert(p);
    log.info("Insert: " + p);

    // Find
    p = template.findById(p.getId(), Person.class);
    log.info("Found: " + p);

    // Update
    template.updateFirst(query(where("name").is("Joe")), update("age", 35), Person.class);
    p = template.findOne(query(where("name").is("Joe")), Person.class);
    log.info("Updated: " + p);

    // Delete
    template.remove(p);

    // Check that deletion worked
    List<Person> people =  template.findAll(Person.class);
    log.info("Number of people = : " + people.size());


    template.dropCollection(Person.class);
  }
}

前面的示例将生成以下日志输出(包括来自以下位置的调试消息):MongoTemplateSpring中文文档

DEBUG apping.MongoPersistentEntityIndexCreator:  80 - Analyzing class class org.spring.example.Person for index information.
DEBUG work.data.mongodb.core.MongoTemplate: 632 - insert Document containing fields: [_class, age, name] in collection: person
INFO               org.spring.example.MongoApp:  30 - Insert: Person [id=4ddc6e784ce5b1eba3ceaf5c, name=Joe, age=34]
DEBUG work.data.mongodb.core.MongoTemplate:1246 - findOne using query: { "_id" : { "$oid" : "4ddc6e784ce5b1eba3ceaf5c"}} in db.collection: database.person
INFO               org.spring.example.MongoApp:  34 - Found: Person [id=4ddc6e784ce5b1eba3ceaf5c, name=Joe, age=34]
DEBUG work.data.mongodb.core.MongoTemplate: 778 - calling update using query: { "name" : "Joe"} and update: { "$set" : { "age" : 35}} in collection: person
DEBUG work.data.mongodb.core.MongoTemplate:1246 - findOne using query: { "name" : "Joe"} in db.collection: database.person
INFO               org.spring.example.MongoApp:  39 - Updated: Person [id=4ddc6e784ce5b1eba3ceaf5c, name=Joe, age=35]
DEBUG work.data.mongodb.core.MongoTemplate: 823 - remove using query: { "id" : "4ddc6e784ce5b1eba3ceaf5c"} in collection: person
INFO               org.spring.example.MongoApp:  46 - Number of people = : 0
DEBUG work.data.mongodb.core.MongoTemplate: 376 - Dropped collection [database.person]
public class ReactiveMongoApplication {

  private static final Logger log = LoggerFactory.getLogger(ReactiveMongoApplication.class);

  public static void main(String[] args) throws Exception {

    CountDownLatch latch = new CountDownLatch(1);

    ReactiveMongoTemplate template = new ReactiveMongoTemplate(MongoClients.create(), "database");

    template.insert(new Person("Joe", 34)).doOnNext(person -> log.info("Insert: " + person))
      .flatMap(person -> template.findById(person.getId(), Person.class))
      .doOnNext(person -> log.info("Found: " + person))
      .zipWith(person -> template.updateFirst(query(where("name").is("Joe")), update("age", 35), Person.class))
      .flatMap(tuple -> template.remove(tuple.getT1())).flatMap(deleteResult -> template.findAll(Person.class))
      .count().doOnSuccess(count -> {
        log.info("Number of people: " + count);
        latch.countDown();
      })

      .subscribe();

    latch.await();
  }
}

MongoConverter通过识别(通过约定)属性名称,在存储在数据库中的 A 和 An 之间进行隐式转换。StringObjectIdIdSpring中文文档

前面的示例旨在演示对 / 上的保存、更新和删除操作的使用,而不是显示复杂的映射功能。 前面的示例中使用的查询语法在“查询文档”一节中有更详细的说明。MongoTemplateReactiveMongoTemplateSpring中文文档

MongoDB要求你有一个所有文档的字段。有关此字段的特殊处理的详细信息,请参阅 ID 处理部分。_id
MongoDB 集合可以包含表示各种类型实例的文档。有关详细信息,请参阅类型映射
MongoDB要求你有一个所有文档的字段。有关此字段的特殊处理的详细信息,请参阅 ID 处理部分。_id
MongoDB 集合可以包含表示各种类型实例的文档。有关详细信息,请参阅类型映射

插入/保存

有几种方便的方法可以保存和插入对象。 为了对转换过程进行更精细的控制,您可以使用 — 例如 和 注册 Spring 转换器。MongoTemplateMappingMongoConverterConverter<Person, Document>Converter<Document, Person>Spring中文文档

插入操作和保存操作之间的区别在于,如果对象尚不存在,则保存操作将执行插入操作。

使用保存操作的简单情况是保存 POJO。 在这种情况下,集合名称由类的名称(非完全限定)确定。 您也可以使用特定的集合名称调用保存操作。可以使用映射元数据来覆盖要存储对象的集合。Spring中文文档

插入或保存时,如果未设置该属性,则假定其值将由数据库自动生成。 因此,要使自动生成 an 成功,类中的属性或字段的类型必须是 、 或 。IdObjectIdIdStringObjectIdBigIntegerSpring中文文档

下面的示例演示如何保存文档并检索其内容:Spring中文文档

使用 MongoTemplate 插入和检索文档
import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Criteria.query;

//...

template.insert(new Person("Bob", 33));

Person person = template.query(Person.class)
    .matching(query(where("age").is(33)))
    .oneValue();
import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Criteria.query;

//...

Mono<Person> person = mongoTemplate.insert(new Person("Bob", 33))
    .then(mongoTemplate.query(Person.class)
        .matching(query(where("age").is(33)))
        .one());

可以使用以下插入和保存操作:Spring中文文档

  • void save :将对象保存到默认集合。(Object objectToSave)Spring中文文档

  • void save :将对象保存到指定的集合。(Object objectToSave, String collectionName)Spring中文文档

此外,还提供一组类似的插入操作:Spring中文文档

  • void insert :将对象插入到默认集合中。(Object objectToSave)Spring中文文档

  • void insert :将对象插入到指定的集合中。(Object objectToSave, String collectionName)Spring中文文档

如何在映射图层中处理字段_id

MongoDB要求你有一个所有文档的字段。 如果未提供,驱动程序将分配具有生成值的值,而不会考虑域模型,因为服务器不知道标识符类型。 使用 时,某些规则控制如何将 Java 类中的属性映射到此字段:_idObjectIdMappingMongoConverter_idSpring中文文档

  1. 用 () 批注的属性或字段映射到该字段。@Idorg.springframework.data.annotation.Id_idSpring中文文档

  2. 没有注释但已命名的属性或字段映射到该字段。id_idSpring中文文档

下面概述了在使用 (默认为 )时对映射到文档字段的属性执行的类型转换(如果有)。_idMappingMongoConverterMongoTemplateSpring中文文档

  1. 如果可能,在 Java 类中声明为 a 的属性或字段将使用 Spring 转换为 a 并存储为 。有效的转换规则委托给MongoDB Java驱动程序。如果无法转换为 ,则该值将作为字符串存储在数据库中。idStringObjectIdConverter<String, ObjectId>ObjectIdSpring中文文档

  2. 在 Java 类中声明为 的属性或字段将使用 Spring 转换为 并存储为 。idBigIntegerObjectIdConverter<BigInteger, ObjectId>Spring中文文档

如果 Java 类中不存在上述规则集中指定的字段或属性,则驱动程序会生成一个隐式文件,但不会映射到 Java 类的属性或字段。_idSpring中文文档

查询和更新时,请使用与上述规则相对应的转换器来保存文档,以便查询中使用的字段名称和类型可以与域类中的内容匹配。MongoTemplateSpring中文文档

某些环境需要自定义方法来映射值,例如存储在 MongoDB 中的数据,这些数据未通过 Spring Data 映射层运行。文档可以包含可表示为 或 的值。 将文档从存储区读回域类型就可以了。由于隐式转换,通过它们查询文档可能很麻烦。因此,无法以这种方式检索文档。 对于这些情况,可以更好地控制实际的 ID 映射尝试。Id_idObjectIdStringidObjectId@MongoIdSpring中文文档

例 1. 映射@MongoId
public class PlainStringId {
  @MongoId String id; (1)
}

public class PlainObjectId {
  @MongoId ObjectId id; (2)
}

public class StringToObjectId {
  @MongoId(FieldType.OBJECT_ID) String id; (3)
}
1 该 ID 将被视为没有进一步转换。String
2 该 ID 被视为 。ObjectId
3 将 id 视为给定的有效十六进制,否则视为 。对应于使用情况。ObjectIdStringObjectIdString@Id

我的文档保存在哪个集合中?

有两种方法可以管理用于文档的集合名称。 使用的默认集合名称是更改为以小写字母开头的类名。 因此,类存储在集合中。 您可以通过在批注中提供不同的集合名称来自定义此名称。 还可以通过提供自己的集合名称作为所选方法调用的最后一个参数来覆盖集合名称。com.test.Personperson@DocumentMongoTemplateSpring中文文档

插入或保存单个对象

MongoDB驱动程序支持在单个操作中插入文档集合。 接口中的以下方法支持此功能:MongoOperationsSpring中文文档

  • insert:插入对象。如果存在具有相同内容的现有文档,则会生成错误。idSpring中文文档

  • insertAll:将 of 对象作为第一个参数。此方法检查每个对象,并根据前面指定的规则将其插入到相应的集合中。CollectionSpring中文文档

  • save:保存对象,覆盖任何可能具有相同 .idSpring中文文档

批量插入多个对象

MongoDB驱动程序支持在一个操作中插入文档集合。 接口中的以下方法通过或专用接口支持此功能。MongoOperationsinsertBulkOperationsSpring中文文档

批处理插入
Collection<Person> inserted = template.insert(List.of(...), Person.class);
Flux<Person> inserted = template.insert(List.of(...), Person.class);
散装插件
BulkWriteResult result = template.bulkOps(BulkMode.ORDERED, Person.class)
    .insert(List.of(...))
    .execute();
Mono<BulkWriteResult> result = template.bulkOps(BulkMode.ORDERED, Person.class)
    .insert(List.of(...))
    .execute();

批处理和批量的服务器性能是相同的。 但是,批量操作不会发布生命周期事件Spring中文文档

在调用 insert 之前未设置的任何属性都将自动初始化(如果是简单类型,如 )或包装器类型(例如 )。
有关详细信息,请参阅乐观锁定部分。
@Version1int0IntegerSpring中文文档

插入操作和保存操作之间的区别在于,如果对象尚不存在,则保存操作将执行插入操作。
1 该 ID 将被视为没有进一步转换。String
2 该 ID 被视为 。ObjectId
3 将 id 视为给定的有效十六进制,否则视为 。对应于使用情况。ObjectIdStringObjectIdString@Id

批处理和批量的服务器性能是相同的。 但是,批量操作不会发布生命周期事件Spring中文文档

在调用 insert 之前未设置的任何属性都将自动初始化(如果是简单类型,如 )或包装器类型(例如 )。
有关详细信息,请参阅乐观锁定部分。
@Version1int0IntegerSpring中文文档

更新

对于更新,您可以使用 using 更新找到的第一个文档,也可以使用该方法或在 Fluent API 上更新找到的所有文档以匹配查询。 以下示例显示了我们使用运算符向余额添加一次性 50.00 美元奖金的所有帐户的更新:MongoOperation.updateFirstMongoOperation.updateMultiallSAVINGS$incSpring中文文档

使用MongoTemplate / ReactiveMongoTemplate
import static org.springframework.data.mongodb.core.query.Criteria.where;
import org.springframework.data.mongodb.core.query.Update;

// ...

UpdateResult result = template.update(Account.class)
    .matching(where("accounts.accountType").is(Type.SAVINGS))
    .apply(new Update().inc("accounts.$.balance", 50.00))
    .all();
import static org.springframework.data.mongodb.core.query.Criteria.where;
import org.springframework.data.mongodb.core.query.Update;

// ...

Mono<UpdateResult> result = template.update(Account.class)
    .matching(where("accounts.accountType").is(Type.SAVINGS))
    .apply(new Update().inc("accounts.$.balance", 50.00))
    .all();

除了前面讨论的内容之外,我们还使用对象提供更新定义。 该类具有与可用于 MongoDB 的更新修饰符匹配的方法。 大多数方法返回对象,以便为 API 提供流畅的样式。QueryUpdateUpdateUpdateSpring中文文档

@Version属性(如果未包含在 中)将自动递增。 有关详细信息,请参阅乐观锁定部分。UpdateSpring中文文档

运行文档更新的方法

  • updateFirst:使用更新的文档更新与查询文档条件匹配的第一个文档。Spring中文文档

  • updateMulti:使用更新的文档更新与查询文档条件匹配的所有对象。Spring中文文档

updateFirst不支持订购。请使用 findAndModify 申请 。Sort
可以通过 提供更新操作的索引提示。Query.withHint(…​)

类中的方法Update

你可以在类中使用一点“语法糖”,因为它的方法应该链接在一起。 此外,您还可以通过使用和使用静态导入来启动新实例的创建。UpdateUpdatepublic static Update update(String key, Object value)Spring中文文档

该类包含以下方法:UpdateSpring中文文档

  • Update addToSet 使用 update 修饰符进行更新(String key, Object value)$addToSetSpring中文文档

  • Update 当前日期 使用 update 修饰符进行更新(String key)$currentDateSpring中文文档

  • Update currentTimestamp 使用 update 修饰符进行更新(String key)$currentDate$type timestampSpring中文文档

  • Update 公司 使用 update 修饰符进行更新(String key, Number inc)$incSpring中文文档

  • Update 麦克斯 使用 update 修饰符进行更新(String key, Object max)$maxSpring中文文档

  • Update 分钟 使用 update 修饰符进行更新(String key, Object min)$minSpring中文文档

  • Update 使用 update 修饰符进行更新(String key, Number multiplier)$mulSpring中文文档

  • Update 流行 使用 update 修饰符进行更新(String key, Update.Position pos)$popSpring中文文档

  • Update 使用 update 修饰符进行更新(String key, Object value)$pullSpring中文文档

  • Update pullAll 使用 update 修饰符进行更新(String key, Object[] values)$pullAllSpring中文文档

  • Update 使用 update 修饰符进行更新(String key, Object value)$pushSpring中文文档

  • Update 推所有 使用 update 修饰符进行更新(String key, Object[] values)$pushAllSpring中文文档

  • Update 重命名 使用 update 修饰符进行更新(String oldName, String newName)$renameSpring中文文档

  • Update 设置 使用 update 修饰符进行更新(String key, Object value)$setSpring中文文档

  • Update setOnInsert 使用 update 修饰符进行更新(String key, Object value)$setOnInsertSpring中文文档

  • Update 未凝固的 使用 update 修饰符进行更新(String key)$unsetSpring中文文档

某些更新修饰符(如 和 )允许嵌套其他运算符。$push$addToSetSpring中文文档

// { $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");

聚合管道更新

更新由 公开的方法,并接受通过 的聚合管道。 使用允许在更新操作中利用 MongoDB 4.2 聚合。 在更新中使用聚合允许通过单个操作表达多个阶段和多个条件来更新一个或多个字段。MongoOperationsReactiveMongoOperationsAggregationUpdateAggregationUpdateSpring中文文档

更新可以包括以下阶段:Spring中文文档

例 2.更新聚合
AggregationUpdate update = Aggregation.newUpdate()
    .set("average").toValue(ArithmeticOperators.valueOf("tests").avg())     (1)
    .set("grade").toValue(ConditionalOperators.switchCases(                 (2)
        when(valueOf("average").greaterThanEqualToValue(90)).then("A"),
        when(valueOf("average").greaterThanEqualToValue(80)).then("B"),
        when(valueOf("average").greaterThanEqualToValue(70)).then("C"),
        when(valueOf("average").greaterThanEqualToValue(60)).then("D"))
        .defaultTo("F")
    );

template.update(Student.class)                                              (3)
    .apply(update)
    .all();                                                                 (4)
db.students.update(                                                         (3)
   { },
   [
     { $set: { average : { $avg: "$tests" } } },                            (1)
     { $set: { grade: { $switch: {                                          (2)
                           branches: [
                               { case: { $gte: [ "$average", 90 ] }, then: "A" },
                               { case: { $gte: [ "$average", 80 ] }, then: "B" },
                               { case: { $gte: [ "$average", 70 ] }, then: "C" },
                               { case: { $gte: [ "$average", 60 ] }, then: "D" }
                           ],
                           default: "F"
     } } } }
   ],
   { multi: true }                                                          (4)
)
1 第一阶段根据测试字段的平均值计算新的字段平均值$set
2 第二阶段根据第一个聚合阶段计算的平均字段计算新的字段等级$set
3 管道在学生集合上运行,并用于聚合字段映射。Student
4 将更新应用于集合中的所有匹配文档。

@Version属性(如果未包含在 中)将自动递增。 有关详细信息,请参阅乐观锁定部分。UpdateSpring中文文档

updateFirst不支持订购。请使用 findAndModify 申请 。Sort
可以通过 提供更新操作的索引提示。Query.withHint(…​)
1 第一阶段根据测试字段的平均值计算新的字段平均值$set
2 第二阶段根据第一个聚合阶段计算的平均字段计算新的字段等级$set
3 管道在学生集合上运行,并用于聚合字段映射。Student
4 将更新应用于集合中的所有匹配文档。

更新插入

与执行操作相关,您还可以执行一项操作,如果没有找到与查询匹配的文档,该操作将执行插入。 插入的文档是查询文档和更新文档的组合。 下面的示例演示如何使用该方法:updateFirstupsertupsertSpring中文文档

UpdateResult result = template.update(Person.class)
  .matching(query(where("ssn").is(1111).and("firstName").is("Joe").and("Fraizer").is("Update"))
  .apply(update("address", addr))
  .upsert();
Mono<UpdateResult> result = template.update(Person.class)
  .matching(query(where("ssn").is(1111).and("firstName").is("Joe").and("Fraizer").is("Update"))
  .apply(update("address", addr))
  .upsert();
upsert不支持订购。请使用 findAndModify 申请 。Sort

@Version属性(如果未包含在 中)将自动初始化。 有关详细信息,请参阅乐观锁定部分。UpdateSpring中文文档

替换集合中的文档

可用的各种方法允许覆盖第一个匹配的文档。 如果未找到匹配项,则可以通过提供相应的配置来更新插入(如上一节所述)。replaceMongoTemplateReplaceOptionsSpring中文文档

更换一个
Person tom = template.insert(new Person("Motte", 21)); (1)
Query query = Query.query(Criteria.where("firstName").is(tom.getFirstName())); (2)
tom.setFirstname("Tom"); (3)
template.replace(query, tom, ReplaceOptions.none()); (4)
1 插入新文档。
2 用于标识要替换的单个文档的查询。
3 设置替换文档,该文档必须与现有文档相同或根本不保存。_id_id
4 运行替换操作。 .用 upsert 替换一个
Person tom = new Person("id-123", "Tom", 21) (1)
Query query = Query.query(Criteria.where("firstName").is(tom.getFirstName()));
template.replace(query, tom, ReplaceOptions.replaceOptions().upsert()); (2)
1 upsert 需要存在该值,否则 MongoDB 将创建一个新的潜在域类型不兼容。 由于MongoDB不知道您的域类型,因此不会考虑任何提示,因此结果可能与您的域模型不兼容。_idObjectId@Field(targetType)ObjectId
2 用于在未找到匹配项时插入新文档upsert

无法通过替换操作更改现有文档。 在 MongoDB 上,使用 2 种方法来确定条目的新 ID: * 在查询中使用,如 * 在替换文档中存在。 如果以任何一种方式提供否,MongoDB 将为文档创建一个新文档。 如果使用的域类型属性具有不同的类型,例如 ._idupsert_id{"_id" : 1234 }_id_idObjectIdidLongSpring中文文档

upsert不支持订购。请使用 findAndModify 申请 。Sort

@Version属性(如果未包含在 中)将自动初始化。 有关详细信息,请参阅乐观锁定部分。UpdateSpring中文文档

1 插入新文档。
2 用于标识要替换的单个文档的查询。
3 设置替换文档,该文档必须与现有文档相同或根本不保存。_id_id
4 运行替换操作。 .用 upsert 替换一个
1 upsert 需要存在该值,否则 MongoDB 将创建一个新的潜在域类型不兼容。 由于MongoDB不知道您的域类型,因此不会考虑任何提示,因此结果可能与您的域模型不兼容。_idObjectId@Field(targetType)ObjectId
2 用于在未找到匹配项时插入新文档upsert

无法通过替换操作更改现有文档。 在 MongoDB 上,使用 2 种方法来确定条目的新 ID: * 在查询中使用,如 * 在替换文档中存在。 如果以任何一种方式提供否,MongoDB 将为文档创建一个新文档。 如果使用的域类型属性具有不同的类型,例如 ._idupsert_id{"_id" : 1234 }_id_idObjectIdidLongSpring中文文档

查找和修改

该方法可以更新文档,并在单个操作中返回旧的或新更新的文档。 提供了四种重载方法,这些方法将 和 类化并从 POJO 转换为 POJO:findAndModify(…)MongoCollectionMongoTemplatefindAndModifyQueryUpdateDocumentSpring中文文档

<T> T findAndModify(Query query, Update update, Class<T> entityClass);

<T> T findAndModify(Query query, Update update, Class<T> entityClass, String collectionName);

<T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass);

<T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass, String collectionName);

下面的示例将几个对象插入到容器中并执行操作:PersonfindAndUpdateSpring中文文档

template.insert(new Person("Tom", 21));
template.insert(new Person("Dick", 22));
template.insert(new Person("Harry", 23));

Query query = new Query(Criteria.where("firstName").is("Harry"));
Update update = new Update().inc("age", 1);

Person oldValue = template.update(Person.class)
  .matching(query)
  .apply(update)
  .findAndModifyValue(); // oldValue.age == 23

Person newValue = template.query(Person.class)
  .matching(query)
  .findOneValue(); // newValye.age == 24

Person newestValue = template.update(Person.class)
  .matching(query)
  .apply(update)
  .withOptions(FindAndModifyOptions.options().returnNew(true)) // Now return the newly updated document when updating
  .findAndModifyValue(); // newestValue.age == 25

该方法允许您设置 、 和 的选项。 从前面的代码片段扩展而来的示例如下:FindAndModifyOptionsreturnNewupsertremoveSpring中文文档

Person upserted = template.update(Person.class)
  .matching(new Query(Criteria.where("firstName").is("Mary")))
  .apply(update)
  .withOptions(FindAndModifyOptions.options().upsert(true).returnNew(true))
  .findAndModifyValue()

@Version属性(如果未包含在 中)将自动递增。 有关详细信息,请参阅乐观锁定部分。UpdateSpring中文文档

@Version属性(如果未包含在 中)将自动递增。 有关详细信息,请参阅乐观锁定部分。UpdateSpring中文文档

查找和替换

替换整体的最直接方法是使用该方法。 但是,这可能并不总是可行的。 提供了一种替代方法,允许通过简单查询来识别要替换的文档。DocumentidsavefindAndReplaceSpring中文文档

例 3.查找和替换文档
Optional<User> result = template.update(Person.class)      (1)
    .matching(query(where("firstame").is("Tom")))          (2)
    .replaceWith(new Person("Dick"))
    .withOptions(FindAndReplaceOptions.options().upsert()) (3)
    .as(User.class)                                        (4)
    .findAndReplace();                                     (5)
1 将 fluent update API 与给定的域类型一起使用,以映射查询并派生集合名称,或者仅使用 .MongoOperations#findAndReplace
2 针对给定域类型映射的实际匹配查询。通过查询提供 和 设置。sortfieldscollation
3 其他可选挂钩,用于提供默认值以外的选项,例如 .upsert
4 用于映射操作结果的可选投影类型。如果给定 None,则使用初始域类型。
5 触发实际处理。用于获取可为 null 的结果,而不是 .findAndReplaceValueOptional
请注意,更换件不得像现有产品那样保持其本身 由商店本身转移到更换。还要记住,这只会替换第一个 根据可能给定的排序顺序与查询条件匹配的文档。ididDocumentfindAndReplace
1 将 fluent update API 与给定的域类型一起使用,以映射查询并派生集合名称,或者仅使用 .MongoOperations#findAndReplace
2 针对给定域类型映射的实际匹配查询。通过查询提供 和 设置。sortfieldscollation
3 其他可选挂钩,用于提供默认值以外的选项,例如 .upsert
4 用于映射操作结果的可选投影类型。如果给定 None,则使用初始域类型。
5 触发实际处理。用于获取可为 null 的结果,而不是 .findAndReplaceValueOptional
请注意,更换件不得像现有产品那样保持其本身 由商店本身转移到更换。还要记住,这只会替换第一个 根据可能给定的排序顺序与查询条件匹配的文档。ididDocumentfindAndReplace

删除

可以使用以下五种重载方法之一从数据库中删除对象:Spring中文文档

template.remove(tywin, "GOT");                                              (1)

template.remove(query(where("lastname").is("lannister")), "GOT");           (2)

template.remove(new Query().limit(3), "GOT");                               (3)

template.findAllAndRemove(query(where("lastname").is("lannister"), "GOT");  (4)

template.findAllAndRemove(new Query().limit(3), "GOT");                     (5)
1 从关联的集合中删除 its 指定的单个实体。_id
2 从集合中删除与查询条件匹配的所有文档。GOT
3 删除集合中的前三个文档。与 <2> 不同,要删除的文档由其标识,运行给定的查询,首先应用 、 和 选项,然后在单独的步骤中一次性删除所有文档。GOT_idsortlimitskip
4 从集合中删除与查询条件匹配的所有文档。与 <3> 不同,文档不会批量删除,而是逐个删除。GOT
5 删除集合中的前三个文档。与 <3> 不同,文档不会批量删除,而是逐个删除。GOT
1 从关联的集合中删除 its 指定的单个实体。_id
2 从集合中删除与查询条件匹配的所有文档。GOT
3 删除集合中的前三个文档。与 <2> 不同,要删除的文档由其标识,运行给定的查询,首先应用 、 和 选项,然后在单独的步骤中一次性删除所有文档。GOT_idsortlimitskip
4 从集合中删除与查询条件匹配的所有文档。与 <3> 不同,文档不会批量删除,而是逐个删除。GOT
5 删除集合中的前三个文档。与 <3> 不同,文档不会批量删除,而是逐个删除。GOT

乐观锁定

注解在MongoDB的上下文中提供了类似于JPA的语法,并确保更新仅应用于具有匹配版本的文档。 因此,将 version 属性的实际值添加到更新查询中,以便如果其他操作在此期间更改了文档,则更新不会产生任何影响。 在这种情况下,将抛出一个。 以下示例显示了这些功能:@VersionOptimisticLockingFailureExceptionSpring中文文档

@Document
class Person {

  @Id String id;
  String firstname;
  String lastname;
  @Version Long version;
}

Person daenerys = template.insert(new Person("Daenerys"));                            (1)

Person tmp = template.findOne(query(where("id").is(daenerys.getId())), Person.class); (2)

daenerys.setLastname("Targaryen");
template.save(daenerys);                                                              (3)

template.save(tmp); // throws OptimisticLockingFailureException                       (4)
1 插入文档。 设置为 。version0
2 加载刚刚插入的文档。 还是.version0
3 使用 更新文档。将 和 bump 设置为 。version = 0lastnameversion1
4 尝试更新之前加载的文档,该文档仍然具有 .操作失败,并显示 ,因为电流为 。version = 0OptimisticLockingFailureExceptionversion1

只有某些 CRUD 操作才会考虑和更改版本属性。有关详细信息,请参阅 java 文档。MongoTemplateMongoOperationsSpring中文文档

乐观锁定需要将 设置为 。否则可以默默吞下。WriteConcernACKNOWLEDGEDOptimisticLockingFailureException
从版本 2.2 开始,还包括从数据库中删除实体时的属性。 要删除没有版本的检查,请使用而不是 。MongoOperations@VersionDocumentMongoOperations#remove(Query,…​)MongoOperations#remove(Object)
从 V2.2 开始,存储库在删除版本控制实体时检查确认删除的结果。 如果无法通过 删除版本化实体,则引发 An 。在这种情况下,版本已更改或对象已同时删除。用于绕过乐观锁定功能并删除对象,无论其版本如何。OptimisticLockingFailureExceptionCrudRepository.delete(Object)CrudRepository.deleteById(ID)
1 插入文档。 设置为 。version0
2 加载刚刚插入的文档。 还是.version0
3 使用 更新文档。将 和 bump 设置为 。version = 0lastnameversion1
4 尝试更新之前加载的文档,该文档仍然具有 .操作失败,并显示 ,因为电流为 。version = 0OptimisticLockingFailureExceptionversion1
乐观锁定需要将 设置为 。否则可以默默吞下。WriteConcernACKNOWLEDGEDOptimisticLockingFailureException
从版本 2.2 开始,还包括从数据库中删除实体时的属性。 要删除没有版本的检查,请使用而不是 。MongoOperations@VersionDocumentMongoOperations#remove(Query,…​)MongoOperations#remove(Object)
从 V2.2 开始,存储库在删除版本控制实体时检查确认删除的结果。 如果无法通过 删除版本化实体,则引发 An 。在这种情况下,版本已更改或对象已同时删除。用于绕过乐观锁定功能并删除对象,无论其版本如何。OptimisticLockingFailureExceptionCrudRepository.delete(Object)CrudRepository.deleteById(ID)