Spring Data Lovelace for MongoDB 有哪些新功能?

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

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

最有趣的新特性可能是 MongoDB 4.0 对 多文档事务 的支持。如果您之前关注过此博客,您可能已经阅读过我们的 实践指南,其中解释了 ClientSessions(它是主要的构建块)和事务本身。简而言之,SpringData 为您提供了利用项目中 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 可以打开其他可能性。到目前为止,在 capped 集合上使用带有 tailable 光标的无限流仅限于反应式 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();

active 标志可能是 "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 社区中所有即将举行的活动。

查看全部