原标题:Spring Data MongoDB参考文档三(内容来源:Spring中国教育管理中心)
自定义类型映射
如果你不想把整个Java类名写成类型信息,而是想用一个key,你可以@TypeAlias在实体类上使用注解。如果你需要更多的自定义映射,看看TypeInformationMapper接口。该接口的实例可以在 上配置DefaultMongoTypeMapper,而后者又可以在 上配置MappingMongoConverter。以下示例显示了如何为实体定义类型别名:
示例 64.为实体定义类型别名
@TypeAlias("pers")class Person { }
请注意,生成的文档包含字段中pers的值_class。
类型别名仅在映射上下文知道实际类型时才有效。所需的实体元数据在第一次保存时确定,或者必须通过配置初始实体集提供。默认情况下,配置类会扫描基础包以寻找潜在的候选者。
@Configuration public class AppConfig extends AbstractMongoClientConfiguration { @Override protected Set<Class<?>> getInitialEntitySet() { return Collections.singleton(Person.class); } // ... }
配置自定义类型映射
下面的例子说明如何配置自定义MongoTypeMapper的MappingMongoConverter:
示例 65.MongoTypeMapper使用 Spring Java Config配置自定义
class CustomMongoTypeMapper extends DefaultMongoTypeMapper { //implement custom type mapping here}
@Configurationclass SampleMongoConfiguration extends AbstractMongoClientConfiguration { @Override protected String getDatabaseName() { return "database"; } @Bean @Override public MappingMongoConverter mappingMongoConverter() throws Exception { MappingMongoConverter mmc = super.mappingMongoConverter(); mmc.setTypeMapper(customTypeMapper()); return mmc; } @Bean public MongoTypeMapper customTypeMapper() { return new CustomMongoTypeMapper(); } }
请注意,前面的示例扩展了
AbstractMongoClientConfiguration类并覆盖了MappingMongoConverter我们配置自定义MongoTypeMapper.
以下示例显示如何使用 XML 配置自定义MongoTypeMapper:
示例 66.MongoTypeMapper使用 XML配置自定义
<mongo:mapping-converter type-mapper-ref="customMongoTypeMapper"/> <bean name="customMongoTypeMapper" class="com.bubu.mongo.CustomMongoTypeMapper"/>
11.5.3.保存和插入文档的方法
有几种方便的方法可MongoTemplate用于保存和插入对象。要对转换过程进行更细粒度的控制,您可以使用MappingMongoConverter - 例如Converter<Person, Document>和注册 Spring 转换器Converter<Document, Person>。
插入和保存操作之间的区别在于,如果对象尚不存在,则保存操作会执行插入操作。
使用保存操作的简单情况是保存一个 POJO。在这种情况下,集合名称由类的名称(非完全限定)确定。您还可以使用特定的集合名称调用保存操作。您可以使用映射元数据来覆盖存储对象的集合。
插入或保存时,如果Id未设置该属性,则假设其值将由数据库自动生成。因此,ObjectId要成功自动生成 an ,类中的Id属性或字段的类型必须是 a String、 anObjectId或 a BigInteger。
以下示例显示了如何保存文档并检索其内容:
示例 67. 使用 MongoTemplate 插入和检索文档
import static org.springframework.data.mongodb.core.query.Criteria.where;import static org.springframework.data.mongodb.core.query.Criteria.query; … Person p = new Person("Bob", 33); mongoTemplate.insert(p); Person qp = mongoTemplate.findOne(query(where("age").is(33)), Person.class);
以下插入和保存操作可用:
void save (Object objectToSave):将对象保存到默认集合。
void save (Object objectToSave, String collectionName):将对象保存到指定的集合。
也可以使用一组类似的插入操作:
void insert (Object objectToSave):将对象插入到默认集合中。
void insert (Object objectToSave, String collectionName):将对象插入到指定的集合中。
我的文档保存在哪个集合中?
有两种方法可以管理用于文档的集合名称。使用的默认集合名称是更改为以小写字母开头的类名称。所以一个com.test.Person类存储在person集合中。您可以通过为@Document注释提供不同的集合名称来对此进行自定义。您还可以通过提供您自己的集合名称作为所选MongoTemplate方法调用的最后一个参数来覆盖集合名称。
插入或保存单个对象
MongoDB 驱动程序支持在单个操作中插入文档集合。MongoOperations接口中的以下方法支持此功能:
insert:插入一个对象。如果存在具有相同 的现有文档,id则会生成错误。
insertAll:将一个Collection对象作为第一个参数。此方法根据之前指定的规则检查每个对象并将其插入到适当的集合中。
save:保存对象,覆盖任何可能具有相同id.
批量插入多个对象
MongoDB 驱动程序支持在一个操作中插入一组文档。MongoOperations接口中的以下方法支持此功能:
插入方法:以 aCollection作为第一个参数。它们在单个批量写入数据库中插入对象列表。
11.5.4.更新集合中的文档
对于更新,您可以使用 using 更新找到的第一个文档,也可以使用
MongoOperation.updateFirst方法更新找到的与查询匹配的所有文档MongoOperation.updateMulti。以下示例显示了SAVINGS我们使用$inc运算符向余额添加一次性 50.00 美元奖金的所有帐户的更新:
示例 68. 使用 MongoTemplate
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);
除了Query前面讨论的之外,我们还通过使用Update对象来提供更新定义。该Update班有匹配供MongoDB的更新改进剂的方法。
大多数方法都会返回Update对象,为 API 提供流畅的样式。
运行文档更新的方法
updateFirst:用更新的文档更新与查询文档条件匹配的第一个文档。
updateMulti:使用更新的文档更新与查询文档条件匹配的所有对象。
updateFirst不支持订购。请使用findAndModify申请Sort。
Update类中的方法
您可以在类中使用一点“'语法糖'” Update,因为它的方法旨在链接在一起。此外,您可以Update通过public static Update update(String key, Object value)使用静态导入来启动新实例的创建。
本Update类包含以下方法:
Update (String key, Object value)使用$addToSet更新修饰符的addToSet更新
Update (String key)使用$currentDateupdate 修饰符更新currentDate
Update currentTimestamp (String key)使用$currentDate更新修饰符更新$type timestamp
Update inc (String key, Number inc)使用$inc更新修饰符更新
Update (String key, Object max)使用$max更新修饰符的最大更新
Update min (String key, Object min)使用$min更新修饰符进行更新
Update (String key, Number multiplier)使用$mul更新修饰符乘以更新
Update (String key, Update.Position pos)使用$pop更新修饰符弹出更新
Update (String key, Object value)使用$pull更新修饰符拉取更新
Update (String key, Object[] values)使用$pullAll更新修饰符pullAll更新
Update (String key, Object value)使用$push更新修饰符推送更新
Update pushAll (String key, Object[] values)使用$pushAll更新修饰符更新
Update (String oldName, String newName)使用$rename更新修饰符重命名更新
Update (String key, Object value)使用$set更新修饰符设置更新
Update (String key, Object value)使用$setOnInsert更新修饰符setOnInsert更新
Update (String key)使用$unset更新修饰符取消设置更新
一些更新修饰符,例如$pushand $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");
11.5.5.“更新”集合中的文档
与执行updateFirst操作相关,您还可以执行“upsert”操作,如果找不到与查询匹配的文档,它将执行插入操作。插入的文档是查询文档和更新文档的组合。以下示例显示了如何使用该upsert方法:
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。
11.5.6.在集合中查找和更新文档
该findAndModify(…)对方法MongoCollection可以更新的文件,并在单个操作中返回老任或新更新的文件。MongoTemplate提供了四个findAndModify重载方法,它们接受Query和Update类并将 from 转换Document为您的 POJO:
<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);
以下示例将一些Person对象插入容器并执行findAndUpdate操作:
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(); // return's old person object assertThat(oldValue.getFirstName()).isEqualTo("Harry"); assertThat(oldValue.getAge()).isEqualTo(23); Person newValue = template.query(Person.class) .matching(query) .findOneValue(); assertThat(newValue.getAge()).isEqualTo(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(); assertThat(newestValue.getAge()).isEqualTo(25);
该FindAndModifyOptions方法可以让你设置的选项returnNew,upsert以及remove从前面的代码片段延伸.An例子如下:
Person upserted = template.update(Person.class) .matching(new Query(Criteria.where("firstName").is("Mary"))) .apply(update) .withOptions(FindAndModifyOptions.options().upsert(true).returnNew(true)) .findAndModifyValue() assertThat(upserted.getFirstName()).isEqualTo("Mary"); assertThat(upserted.getAge()).isOne();
11.5.7.聚合管道更新
更新方法公开MongoOperations并通过聚合管道ReactiveMongoOperations接受聚合管道AggregationUpdate。UsingAggregationUpdate允许在更新操作中利用MongoDB 4.2 聚合。在更新中使用聚合允许通过使用单个操作表达多个阶段和多个条件来更新一个或多个字段。
更新可以包括以下阶段:
AggregationUpdate.set(…).toValue(…) → $set : { … }
AggregationUpdate.unset(…) → $unset : [ … ]
AggregationUpdate.replaceWith(…) → $replaceWith : { … }
示例 69. 更新聚合
AggregationUpdate update = Aggregation.newUpdate() .set("average").toValue(ArithmeticOperators.valueOf("tests").avg()) .set("grade").toValue(ConditionalOperators.switchCases( 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) .apply(update) .all();
db.students.update( { }, [ { $set: { average : { $avg: "$tests" } } }, { $set: { grade: { $switch: { 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 } )
第一$set阶段根据测试字段的平均值计算新的字段平均值。
第二$set阶段根据第一聚合阶段计算的平均字段计算新的字段等级。
管道在学生集合上运行并Student用于聚合字段映射。
将更新应用于集合中的所有匹配文档。
11.5.8.查找和替换文档
替换整个的最直接的方法Document是通过它idusingsave方法。然而,这可能并不总是可行的。findAndReplace提供了一种替代方法,允许通过简单的查询来识别要替换的文档。
示例 70. 查找和替换文档
Optional<User> result = template.update(Person.class) .matching(query(where("firstame").is("Tom"))) .replaceWith(new Person("Dick")) .withOptions(FindAndReplaceOptions.options().upsert()) .as(User.class) .findAndReplace();
使用具有给定域类型的 fluent update API 来映射查询和派生集合名称,或者仅使用MongoOperations#findAndReplace.
映射到给定域类型的实际匹配查询。通过查询提供sort,fields和collation设置。
额外的可选钩子以提供默认值以外的选项,如upsert.
用于映射运算结果的可选投影类型。如果没有给出初始域类型,则使用。
触发实际处理。使用findAndReplaceValue以获得可空的结果,而不是一个Optional。
请注意,更换件不得保留其id本身,因为id现有的Document将被商店本身转移到更换件中。还要记住,它findAndReplace只会根据可能给定的排序顺序替换与查询条件匹配的第一个文档。