在Spring Data MongoDB中實現關係建模 - spring.io
如何在 Spring Data MongoDB 中使用Manual references和 DBRefs建模關係的實用指南。
- DBRef是 MongoDB 的本機元素,用於以顯式格式表達對其他文件的引用,該格式{ $db : …, $ref : …, $id : … }儲存有關目標資料庫、集合和引用元素的id值的資訊,最適合連結到分佈在不同集合中的文件。
- Manual references手動引用在結構上更簡單(通過僅儲存被引用文件的id),但因此在混合集合引用時不那麼靈活。
讓我們介紹眾所周知的域型別,例如Bookand Publisher,以及它們之間的明顯關係:
class Book { private String isbn13; private String title; private int pages; } class Publisher { private String name; private String arconym; private int foundationYear; } |
將每個Publisher嵌入到每個Book中並不是一個有吸引力的選擇,因為它會導致資料重複並對儲存和可維護性造成不必要的負擔:
class Book { // ... private Publisher publisher; } |
儘管這種儲存格式允許原子更新並在查詢特定屬性時提供最大的靈活性,但如下面的片段所示,資訊的重複可能不值得付出這樣的代價:
{ "_id" : "617cfb", "isbn13" : "978-0345503800", "title" : "The Warded Man", "pages" : 432, "publisher" : { "name" : "Del Rey Books", "arconym" : "DRB", "foundationYear" : 1977 } } |
規範化模型並使用連結文件可以緩解這個問題。
第一步是確定關係的方向,以確定關係的哪一部分需要儲存引用,如果不是兩者都需要。此決定將影響我們稍後可用的查詢、儲存和查詢選項。
使用DBRef 連結
Publisher持有引用關聯的Books. 這個想法是將這些引用儲存為Publisher文件中的陣列:
class Publisher { // ... @DBRef List<Book> books; } |
在上面的程式碼片段中,books 屬性用@DBRef. 這建議 Spring Data 對映層將屬性的元素儲存為 MongoDB 本機$dbref元素,如下所示:
{ "_id" : "833f7d", "name" : "Del Rey Books", "arconym" : "DRB", "foundationYear" : 1977, "books" : [ { "$ref" : "book", "$id" : "617cfb" }, { "$ref" : "book", "$id" : "23e78f" } ] } |
使用@DBRef註釋可以通過不重複Book 中的所有Publisher資訊來減少儲存大小。
儘管如此,這種方法也有其缺點。Book將不再持有Publisher資訊,可能會影響按出版商Publisher屬性查詢書籍Book的查詢。
缺少對Publisher的反向引用也會影響效能。
有一些方法可以改進,首先是新增對 Publisher 的反向引用(例如,通過它的id):
class Book { // … private String publisherId; } |
使用Manual References
讓我們從DBRef切換到Manual References來儲存引用的集合Book。顯而易見的步驟是刪除@DBRef註釋並將 替換List<Book>為List<String>。
class Publisher { // … List<String> bookIds; } |
{ … "bookIds" : ["617cfb", "23e78f", … ] } |
要新增一個新的Book到Publisher 的bookIds欄位,我們可以使用以下語句。
template.update(Publisher.class) .matching(where("id").is(publisher.id)) .apply(new Update().push("bookIds", book.id)) .first(); |
遵循這種方法優化了儲存格式,並對域模型和資料庫中使用的資料型別做出了非常明確的宣告。
然而,只有一個bookIds不會為您提供在其中查詢bookIds欄位中包含的值的集合的上下文。
使用宣告性手冊參考引用 (Declarative Manual References)
從Spring Data MongoDB 3.3.0 開始,手動引用可以通過使用@DocumentReference註釋以宣告方式表示:
class Publisher { // … @DocumentReference List<Book> books; } |
預設情況下,這會告訴對映層提取引用實體的id值進行儲存,在讀取時載入引用文件本身。
{ … "books" : ["617cfb", … ] } |
此外,可以通過這種方式對來自Book到Publisher的反向引用進行建模。在這種情況下,將釋出者的檢索延遲到第一次訪問該屬性以避免急切載入延遲可能是有意義的:
class Book { // … @DocumentReference(lazy=true) private Publisher publisher; } |
通過使用宣告性引用,我們現在可以在優化儲存的同時保留對映功能。不過,我們在新增新Book例項時需要小心,因為那些也需要新增到 Publisher的books欄位中以建立連結:
template.save(newBook); template.update(Publisher.class) .matching(where("id").is(newBook.publisher.id)) .apply(new Update().push("books", newBook)) .first(); |
上面的程式碼片段很好地概述了處理文件之間連結的非原子性質,這可能需要在Transaction 中執行操作。
一對多樣式引用
根據應用程式的需要,可以反轉Book和Publisher之間的關係,以便將連結元素單獨儲存在Book文件中。這使您可以儲存Book,而無需考慮更新Publisher,正如我們在上一個片段中看到的那樣。為此,我們需要做兩件事。首先,我們需要告訴對映層省略儲存從Publisher到Book的連結,其次,在獲取Book引用時更新查詢查詢。
對books屬性應用附加@ReadOnlyPorperty註釋;另一部分要求我們使用自定義查詢更新@DocumentReference註釋的lookup屬性:
class Publisher { // … @ReadOnlyProperty @DocumentReference(lookup="{'publisher':?#{self._id} }") List<Book> books; } |
在上面的程式碼片段中,我們利用了 Spring Data 查詢解析器中的表示式支援。這樣做時,我們可以使用self屬性訪問Publisher原始文件,並可以提取其識別符號,然後在查詢與其相匹配的Book集合時使用這個標識。
原文見標題
相關文章
- MongoDB 關係實現MongoDB
- spring data mongodb配置+月庫實現SpringMongoDB
- Spring Data Moore有哪些新功能? - spring.ioSpring
- 關係建模ER建模-維度建模
- Spring Data JPA 實現多表關聯查詢Spring
- spring-data-mongodb常用操作SpringMongoDB
- SpringBoot 整合 Spring Data Mongodb 操作 MongoDB 詳解Spring BootMongoDB
- Spring Data JDBC如何對DDD聚合根進行部分更新? - spring.ioSpringJDBC
- Spring認證中國教育管理中心-Spring Data MongoDB教程SpringMongoDB
- Spring Data JPA中實現更新插入三種方法Spring
- 在Spring專案中如何處理R2DBC的實體關係? - sipiosSpringiOS
- 現在是時候了與Spring Boot 1.x說再見了! - spring.ioSpring Boot
- 使用Spring Data JDBC實現DDD聚合SpringJDBC
- Spring Cloud Stream事件路由 - spring.ioSpringCloud事件路由
- Spring Cloud Gateway入門 - spring.ioSpringCloudGateway
- Spring Data JPA 實現聯表查詢Spring
- Spring Data MongoDB 操作 document DB 的詳細示例SpringMongoDB
- 如何在Spring Data MongoDB 中儲存和查詢動態欄位SpringMongoDB
- 在Spring Boot中實現WebSocket實時通訊Spring BootWeb
- 實現 MongoDB 外來鍵關聯MongoDB
- Spring Data JPA 之 一對一,一對多,多對多 關係對映Spring
- Spring Data JPA中TransactionInterceptorSpring
- Spring Data JPA中ConfigurableTransactionManagerSpring
- 重要版本Spring Boot 2.3.0釋出 - spring.ioSpring Boot
- Spring Cloud與Spring Boot版本匹配關係CloudSpring Boot
- Geospatial Data 在 Nebula Graph 中的實踐
- 在Spring Boot中實現OAuth2.0認證Spring BootOAuth
- 在spring boot中整合微服務閘道器係統Spring Cloud ZuulSpring Boot微服務CloudZuul
- RSocket入門:Spring Boot伺服器 -Spring.ioSpring Boot伺服器
- 聊聊非關係型資料庫MongoDB索引資料庫MongoDB索引
- nodejs之MongoDB 非關係型資料庫NodeJSMongoDB資料庫
- MongoDB 在評論中臺的實踐MongoDB
- 如何使用Spring Boot,Spring Data和H2 DB實現REST APISpring BootRESTAPI
- Spring Data Redis 最佳實踐!SpringRedis
- Spring Cloud Stream與Spring Integration整合以及Spring Cloud Function的關係:開啟從基於註釋到函數語言程式設計的漫長轉換 - spring.ioSpringCloudFunction函數程式設計
- SpringMVC+Spring Data JPA實現增刪改查操作SpringMVC
- 使用Spring Data JPA實現DDD聚合的動態投影Spring
- Spring Data JPA框架的Repository自定義實現詳解Spring框架