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 中引入了 變更流,以取代目前使用完善的解決方案 tailing 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 集合上使用具有可追蹤游標的無限流僅限於反應式 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 架構的支援來擴充此驗證,這可讓您以更物件導向的方式定義文件藍圖。

{
  "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 社群中所有即將舉辦的活動。

查看全部