在MongoDB中存儲分層數據

繼續使用MongoDB進行 NoSQL之旅,我想觸摸一個經常出現的特定用例:存儲分層文檔關系。 MongoDB是很棒的文檔數據存儲,但是如果文檔具有父子關系怎么辦? 我們可以有效地存儲和查詢此類文檔層次結構嗎? 答案是肯定的,我們可以。 MongoDB對如何在MongoDB中存儲樹提出了一些建議。 那里描述的并且廣泛使用的一種解決方案是使用物化路徑。

讓我通過提供非常簡單的示例來解釋其工作原理。 如前幾篇文章所述,我們將使用最近發布的Spring Data MongoDB項目的1.0版來構建Spring應用程序。 我們的POM文件包含非常基本的依賴性,僅此而已。

4.0.0mongodbcom.example.spring0.0.1-SNAPSHOTjarUTF-83.0.7.RELEASEorg.springframework.dataspring-data-mongodb1.0.0.RELEASEorg.springframeworkspring-beansorg.springframeworkspring-expressioncglibcglib-nodep2.2log4jlog4j1.2.16org.mongodbmongo-java-driver2.7.2org.springframeworkspring-core${spring.version}org.springframeworkspring-context${spring.version}org.springframeworkspring-context-support${spring.version}org.apache.maven.pluginsmaven-compiler-plugin2.3.21.61.6

為了正確配置Spring上下文,我將使用利用Java類的配置方法。 我越來越提倡使用這種樣式,因為它提供了強大的類型化配置,并且大多數錯誤都可以在編譯時發現,而無需再檢查XML文件。 這里看起來像:

package com.example.mongodb.hierarchical;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoFactoryBean;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;@Configuration
public class AppConfig {@Beanpublic MongoFactoryBean mongo() {final MongoFactoryBean factory = new MongoFactoryBean();factory.setHost( "localhost" );return factory;}@Beanpublic SimpleMongoDbFactory mongoDbFactory() throws Exception{return new SimpleMongoDbFactory( mongo().getObject(), "hierarchical" );}@Beanpublic MongoTemplate mongoTemplate() throws Exception {return new MongoTemplate( mongoDbFactory() );}@Beanpublic IDocumentHierarchyService documentHierarchyService() throws Exception {return new DocumentHierarchyService( mongoTemplate() );}
}

很好,很清楚。 謝謝, 春天的家伙! 現在,所有樣板文件已準備就緒。 讓我們轉到有趣的部分:文檔。 我們的數據庫將包含“文檔”集合,其中存儲了SimpleDocument類型的文檔。 我們使用針對SimpleDocument POJO的Spring Data MongoDB批注對此進行描述。

package com.example.mongodb.hierarchical;import java.util.Collection;
import java.util.HashSet;import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;@Document( collection = "documents" )
public class SimpleDocument {public static final String PATH_SEPARATOR = ".";@Id private String id;@Field private String name;@Field private String path;// We won't store this collection as part of document but will build it on demand@Transient private Collection< SimpleDocument > documents = new HashSet< SimpleDocument >();public SimpleDocument() {}public SimpleDocument( final String id, final String name ) {this.id = id;this.name = name;this.path = id;}public SimpleDocument( final String id, final String name, final SimpleDocument parent ) {this( id, name );this.path = parent.getPath() + PATH_SEPARATOR + id;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPath() {return path;}public void setPath(String path) {this.path = path;}public Collection< SimpleDocument > getDocuments() {return documents;}
}

讓我在這里解釋幾件事。 首先,魔術屬性路徑 :這是構造和查詢層次結構的關鍵。 路徑包含所有文檔父級的標識符,通常以某種分隔符(在我們的情況下為)分隔 (點) 。 以這種方式存儲文檔層次結構關系可以快速構建層次結構,進行搜索和導航。 其次,注意臨時文檔集合:此非持久集合是由持久提供程序構造的,并且包含所有后代文檔(以防萬一,還包含自己的后代)。 讓我們通過查找find方法實現來實際觀察它:

package com.example.mongodb.hierarchical;import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;public class DocumentHierarchyService {private MongoOperations template;public DocumentHierarchyService( final MongoOperations template ) {this.template = template;}@Overridepublic SimpleDocument find( final String id ) {final SimpleDocument document = template.findOne(Query.query( new Criteria( "id" ).is( id ) ),SimpleDocument.class);if( document == null ) {return document;}return build(document,template.find(Query.query( new Criteria( "path" ).regex( "^" + id + "[.]" ) ),SimpleDocument.class));}private SimpleDocument build( final SimpleDocument root, final Collection< SimpleDocument > documents ) {final Map< String, SimpleDocument > map = new HashMap< String, SimpleDocument >();for( final SimpleDocument document: documents ) {map.put( document.getPath(), document );}for( final SimpleDocument document: documents ) {map.put( document.getPath(), document );final String path = document.getPath().substring( 0, document.getPath().lastIndexOf( SimpleDocument.PATH_SEPARATOR ) );if( path.equals( root.getPath() ) ) {root.getDocuments().add( document );} else {final SimpleDocument parent = map.get( path );if( parent != null ) {parent.getDocuments().add( document );}}}return root;}
}

如您所見,要獲得具有整個層次結構的單個文檔,我們只需要運行兩個查詢(但更優化的算法可以將其縮減為一個查詢)。 這是一個示例層次結構,以及從MongoDB讀取根文檔的結果

template.dropCollection( SimpleDocument.class );final SimpleDocument parent = new SimpleDocument( "1", "Parent 1" );
final SimpleDocument child1 = new SimpleDocument( "2", "Child 1.1", parent );
final SimpleDocument child11 = new SimpleDocument( "3", "Child 1.1.1", child1 );
final SimpleDocument child12 = new SimpleDocument( "4", "Child 1.1.2", child1 );
final SimpleDocument child121 = new SimpleDocument( "5", "Child 1.1.2.1", child12 );
final SimpleDocument child13 = new SimpleDocument( "6", "Child 1.1.3", child1 );
final SimpleDocument child2 = new SimpleDocument( "7", "Child 1.2", parent );template.insertAll( Arrays.asList( parent, child1, child11, child12, child121, child13, child2 ) );...final ApplicationContext context = new AnnotationConfigApplicationContext( AppConfig.class );
final IDocumentHierarchyService service = context.getBean( IDocumentHierarchyService.class );final SimpleDocument document = service.find( "1" );
//  Printing document show following hierarchy:
//
//  Parent 1
//   |-- Child 1.1
//     |-- Child 1.1.1
//     |-- Child 1.1.3
//     |-- Child 1.1.2
//       |-- Child 1.1.2.1
//   |-- Child 1.2

而已。 簡單一個強大的概念。 當然,在路徑屬性上添加索引將大大加快查詢速度。 有很多改進和優化,但是基本思想現在應該很清楚。

參考: Andriy Redko {devmind}博客上的JCG合作伙伴 Andrey Redko 在MongoDB中存儲分層數據 。


翻譯自: https://www.javacodegeeks.com/2012/01/storing-hierarchical-data-in-mongodb.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/373572.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/373572.shtml
英文地址,請注明出處:http://en.pswp.cn/news/373572.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

圖的深度遍歷

圖的深度遍歷 Time Limit: 1000MS Memory Limit: 65536KBSubmit StatisticProblem Description 請定一個無向圖&#xff0c;頂點編號從0到n-1&#xff0c;用深度優先搜索(DFS)&#xff0c;遍歷并輸出。遍歷時&#xff0c;先遍歷節點編號小的。Input 輸入第一行為整數n&#xff…

Linux學習筆記——gzip命令

這個 gzip 程序被用來壓縮一個或多個文件。當執行 gzip 命令時&#xff0c;則原始文件的壓縮版會替代原始文件。 相對應的 gunzip 程序被用來把壓縮文件復原為沒有被壓縮的版本。gzip 選項&#xff1a;選項 說明-c把輸出寫入到標準輸出&#xff0c;并且保留原始文件。也有可能用…

java集合類——Stack類

查看java的API文檔&#xff0c;Stack繼承Vector類。 棧的特點是后進先出。 API中Stack自身的方法不多&#xff0c;基本跟棧的特點有關。 Java代碼 import java.util.Stack; public class StackTest { public static void main(String[] args) { Stack&l…

免裝版_無縫貼圖制作軟件 PixPlant2中文免裝版

點擊上方藍字關注我們如您喜歡我們的公眾號&#xff0c;不妨推薦給身邊的朋友資源介紹&#xff1a;資源來源于網絡&#xff0c;很多時候我們從網上找的貼圖并不是無縫的&#xff0c;而且一般都沒有高光/法線貼圖這些&#xff0c;在材質的模擬上就要差了很多&#xff0c;在這里小…

網頁特效:用CSS3制作3D圖片立方體旋轉特效

<!DOCTYPE html> <html> <head> <meta charset"utf-8" /> <title>CSS3制作3D圖片立方體旋轉特效 - 站長素材</title><style type"text/css">html{background:linear-gradient(#ff0 0%,#F00 80%);height: 100%; …

Java中使用Map and Fold進行功能性編程

在函數式編程中&#xff0c;Map和Fold是兩個非常有用的運算符&#xff0c;它們屬于每種函數式語言。 如果Map和Fold運算符是如此強大且必不可少&#xff0c;那么您如何解釋說即使Java編程語言缺少這兩個運算符&#xff0c;我們也可以使用Java來完成工作&#xff1f; 事實是&…

Linux 文件壓縮解壓縮

文章來自&#xff1a;http://www.xuexiyuan.cn/article/detail/53.html *.tar格式 解包1&#xff1a;$ tar -xvf FileName.tar解包2&#xff1a;$ tar -xvf FileName.tar -C DirName# tar解壓縮到指定目錄打包&#xff1a;$ tar -cvf FileName.tar DirName# tar是打包&#x…

Mysql 分頁語句Limit用法

Mysql 分頁語句Limit用法 1、Mysql的limit用法 在我們使用查詢語句的時候&#xff0c;經常要返回前幾條或者中間某幾行數據&#xff0c;這個時候怎么辦呢&#xff1f;不用擔心&#xff0c;mysql已經為我們提供了這樣一個功能。 Sql代碼 SELECT * FROM table LIMIT [offset,] r…

sqlmap指定cookie_利用SQLMap進行cookie注入

SQLMap被稱為注入神器&#xff0c;N多大神都使用SQLmap來進行注入測試&#xff0c;我等小菜當然也會用來裝一下A*C&#xff0c;用了N久SQLMAP了&#xff0c;但是極少用 到cookie注入&#xff0c;一遇到cookie注入就去使用注入中轉工具&#xff0c;比較麻煩。剛好今天群里的USB問…

c語言else匹配問題

1 #include <stdio.h>2 #include <stdlib.h>3 4 //實現 依次輸入三個遞增的數 然后正確輸出5 6 //為什么得不到我們想要的結果呢 這就是else匹配的問題 當然了 在編譯器里面他會自動給你匹配7 //但是如果沒有了編譯器 筆試的時候呢。。。。8 //原因為&#xff1a;e…

Java:偽造工廠的閉包以創建域對象

最近&#xff0c;我們想要創建一個域對象&#xff0c;該對象需要具有外部依賴關系才能進行計算&#xff0c;并且希望能夠在測試中解決該依賴關系。 最初&#xff0c;我們只是在領域類中新建依賴項&#xff0c;但這使得無法在測試中控制其值。 同樣&#xff0c;我們似乎不應該將…

利用scp 遠程上傳下載文件/文件夾

利用scp傳輸文件 1、從服務器下載文件 scp usernameservername:/path/filename /tmp/local_destination 例如scp codinglog192.168.0.101:/home/kimi/test.txt 把192.168.0.101上的/home/kimi/test.txt 的文件下載到 /tmp/local_destination 2、上傳本地文件到服務器 scp /…

KEIL編譯錯誤總結:

1 expected an identifier&#xff1a;#define宏定義常量后&#xff0c;如果再用前面定義的常量作為枚舉常量就會報錯&#xff0c;方法&#xff0c;去掉#define宏定義 2 ERROR L118: REFERENCE MADE TO ERRONEOUS EXTERNAL 定義的變量和外部聲明調用的變量存儲類型不一致&#…

視覺平衡與物理平衡_設計中的平衡理論為什么這么重要?

原標題&#xff1a;設計中的平衡理論為什么這么重要&#xff1f;在平面設計中很重要的理論就是關于平衡的應用。無論在logo設計還是網頁設計還是海報設計中&#xff0c;一個好的設計一定會兼顧視覺的平衡。今天123標志網就跟大家一起看看平衡的力量。構圖平衡主要意味著調整設計…

Tomcat、JDK 歷史版本下載地址

Tomcat 歷史版本下載地址http://archive.apache.org/dist/tomcat/ JDK 歷史版本下載地址 https://www.oracle.com/technetwork/java/javase/archive-139210.html 個人博客&#xff1a;學習園 原文地址&#xff1a;http://www.xuexiyuan.cn/article/detail/190.html

JavaFX移動應用程序最佳實踐,第2部分

警告&#xff1a;我在這里給出的技巧對于JavaFX Mobile的當前版本是正確的&#xff0c;該版本是JavaFX 1.1 SDK的一部分。 在將來的版本中&#xff0c;行為將改變&#xff0c;上述工件的當前不良性能將被優化或至少得到顯著改善。 我在這里寫的所有內容都是快照&#xff0c;不應…

14軟件工程第一次作業

你認為一些軍事方面的軟件系統采用什么樣的開發模型比較合適&#xff1f; 我認為設計軍事方面的軟件采用螺旋式的開發模型比較好。因為螺旋模型減少了過多測試或者是測試不足所帶來的風險&#xff0c;能夠使軟件在無法排除重大風險時有機會停止&#xff0c;減少損失。對于軍事方…

波紋擴散_C4D_動畫amp;RS波紋擴散效果J_014

C4D-效果擴散效果&#xff0c;Redshift混合冰材質&#xff1b;利用頂點貼圖擴散效果制作&#xff0c;RS混合調用頂點貼圖。視頻教程時長22分鐘。對象為可編輯對象才能用頂點貼圖。冰結域的擴展是這個動畫的重點&#xff0c;在這個模式下&#xff0c;權重會根據半徑向外擴展&…

軟件測試工程師簡歷項目經驗怎么寫?--9999個已成功入職的軟件測試工程師真實簡歷

簡歷是我們求職的第一步&#xff0c;也是非常重要的一步。 青云叔叔看過太多簡歷&#xff0c;最快3秒就淘汰一份簡歷&#xff0c;因為其實我們每天要收到很多簡歷進行篩選&#xff0c;那么面試官其實也是會很快進行對簡歷進行判斷的&#xff0c;如果你對簡歷寫的一塌糊涂&…

【poj2464】樹狀數組

這道題。。太特么多細節了。。 題意&#xff1a;在平面直角坐標系中給你N個點&#xff0c;stan和ollie玩一個游戲&#xff0c;首先stan在豎直方向上畫一條直線&#xff0c;該直線必須要過其中的某個點&#xff0c;然后ollie在水平方向上畫一條直線&#xff0c;該直線的要求是要…