Spring Data Lovelace for MongoDB 的新增功能

工程 | Christoph Strobl | 2018年9月27日 | ...

过去一年,NoSQL 存储库进行了许多增强,包括许多新功能和扩展的功能。我们与 MongoDB 的驱动程序团队密切合作,因此该版本已经提供了对会话、更改流、模式验证和(当然)事务的良好支持。

最有趣的新功能可能是 MongoDB 4.0 对多文档事务的支持。如果您之前关注过此博客,您可能已经阅读过我们的实践指南,该指南解释了ClientSessions(这是主要构建块)和事务本身。简而言之,Spring Data 为您提供了利用Spring 托管事务支持所需的一切。要使用它,请在您的配置中声明MongoTransactionManager,如下例所示

@Configuration
class Config extends AbstractMongoConfiguration {

  @Bean
  MongoTransactionManager transactionManager(MongoDbFactory dbFactory) {
    return new MongoTransactionManager(dbFactory);
  }
}

事务在快照之上运行,因此,在事务期间进行的更改在 oplog 中看起来有点奇怪。值得庆幸的是,MongoDB 3.6 中引入了更改流,以使用能够在事务期间解开条目的良好支持的解决方案替换当前的 oplog 尾随。更改流允许您在数据库甚至集合级别发生特定事件时获得通知。它提供了一种通过使用聚合来过滤事件的方法,还可以让您在给定的检查点或时间戳处恢复流。使用响应式 API 使用更改流感觉最自然,如下例所示

Flux changeStream = reactiveTemplate
  .changeStream(newAggregation(match(where("operationType").is("insert"))),
    Person.class, ChangeStreamOptions.empty(), "users");

前面的流仅返回插入到users集合中的新文档,并将这些文档映射到Person域类型。要通过使用同步 API 实现相同的功能,需要创建一个长时间运行的阻塞任务,该任务需要委托给一个单独的组件,一个MessageListenerContainer,如下例所示

MessageListenerContainer container =
  new DefaultMessageListenerContainer(template);
container.start();

MessageListener<ChangeStreamDocument<Document>, Person> listener =
  System.out::println;

ChangeStreamRequest request = ChangeStreamRequest.builder()
  .collection("users")
  .filter(newAggregation(match(where("operationType").is("insert")))
  .publishTo(listener)
  .build();

container.register(request, Person.class);

// …

container.stop();

有了MessageListenerContainer,就可以打开其他可能性。到目前为止,使用带有限制集合上的可尾随游标的无限流仅限于响应式 API。现在,只需将SubscriptionRequest传递给容器即可,如下例所示

MessageListener<Document, Person> listener = System.out::println;

TailableCursorRequest request = TailableCursorRequest.builder()
  .collection("users")
  .filter(query(where("active").eq(true)))
  .publishTo(listener)
  .build();

container.register(request, Person.class);

前面的代码段侦听users集合上的插入并在控制台上发布Messages。MongoDB 在一段时间内允许通过使用遵循整体查询语法的验证器来验证添加到集合或在集合中更新的文档。在其新版本中,MongoDB 通过添加对JSON Schema的支持扩展了此验证,这使您能够以更面向对象的方式定义文档蓝图。

{
  "type": "object",
  "required": [ "lastname" ],
  "properties": {
    "lastname": {
      "type": "string"
    },
    "address": {
      "type": "object",
      "properties": {
        "postCode": { "type": "string", "minLength": 4, "maxLength": 5 }
      }
    }
  }
}

MongoJsonSchema及其构建器是 Spring Data API 网关,用于为您的集合定义模式。以下示例显示了如何使用它

MongoJsonSchema jsonSchema = MongoJsonSchema.builder()
  .required("lastname")
  .properties(
     string("lastname"),
     object("address")
       .properties(string("postCode").minLength(4).maxLength(5))
  ).build();

CollectionOptions options = CollectionOptions.empty().schema(jsonSchema);

template.createCollection(Person.class, options);

尽管如此,MongoDB 作为无模式存储,允许字段在每个文档级别具有不同的类型。您还可以使用模式查询与蓝图匹配的文档,而无需强制对集合进行验证,如下例所示

template.query(Person.class)
  .matching(query(matchingDocumentStructure(jsonSchema))).all();

MongoDB 模块的另一个较小但明显的增强以不同值查询的形式出现,这些查询允许您检索分配给单个字段的所有值的唯一列表。如前所述,字段不必具有相同的数据类型。因此,默认情况下,distinct返回一个未类型化的Collection。以下示例显示了如何使用distinct

List<Object> distinctValues = template.query(Person.class)
  .distinct("active")
  .all();

活动标志可能是“y/n”、“true/false”和“0/1”对的混合,在存储本身中分别表示为Stringboolean和(可能)int32。但是,在您至少确定属性类型的情况下,使用as投影获取强类型集合可能很有用。以下示例使用as投影

List<Boolean> distinctValues = template.query(Person.class)
  .distinct("active")
  .as(Boolean)
  .all();

MongoDB 模块中还有一些其他增强功能,但我们没有足够的空间在此处介绍它们。请务必查看参考文档中的新功能部分,以了解有关响应式 MapReduce、默认排序、findAndReplace(…)方法以及新的聚合运算符和阶段的更多信息。

获取 Spring 新闻通讯

与 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,以加速您的进步。

了解更多

获得支持

Tanzu Spring 在一个简单的订阅中提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部