继续使用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

在MongoDB中存储分层数据相关推荐

  1. mongodb存储数据_在MongoDB中存储分层数据

    mongodb存储数据 继续使用MongoDB进行 NoSQL之旅,我想谈一谈一个经常出现的特定用例:存储分层文档关系. MongoDB是很棒的文档数据存储,但是如果文档具有父子关系,该怎么办? 我们 ...

  2. vuex-along解决vuex中存储的数据在页面刷新之后失去的问题

    vuex-along解决vuex中存储的数据在页面刷新之后失去的问题 参考文章: (1)vuex-along解决vuex中存储的数据在页面刷新之后失去的问题 (2)https://www.cnblog ...

  3. JSP、EL和JSTL-学习笔记03【EL介绍和运算符、EL获取域中存储的数据】

    Java后端 学习路线 笔记汇总表[黑马程序员] JSP.EL和JSTL-学习笔记01[JSP基础语法] JSP.EL和JSTL-学习笔记02[MVC] JSP.EL和JSTL-学习笔记03[EL介绍 ...

  4. php数据存储mysql_php – 在MySQL中存储路线数据的最佳方式

    我正在开发一个应用程序,它要求我存储一些位置的方向,下面是我试图存储的数据的示例: 方向1 从西部:乘528 East(Beechline),经过机场出口,然后从13号出口驶入Narcoossee R ...

  5. mysql单价乘以数量_数据库字段中存储的数据数量乘以不同单价的和的算法示例...

    数据库字段中存储的数据数量乘以不同单价的和的算法,适用于记账本程序的计件数据记录,和商品记录等场景. 代码示例如下: //模拟数据库结果集 $arr = array( array( "id& ...

  6. AutoCAD .Net 在dwg文件中存储自定义数据

    问题 我需要在 dwg 文件中存储一些信息,以额外描述图形文件并使它能够和其它软件程序集成. 请问怎样才能在 dwg 文件中写入自定义数据并读取? 回答 你可以使用 Named Object Dict ...

  7. java存储json到mongo_使用spring在mongodb中存储JSON模式

    我是 Spring数据和mongodb的新手.我有一个表示 JSON模式的 JSON对象,我需要使用spring数据将其存储在mongodb中.但JSON模式的问题是JSON Schema的结构是动态 ...

  8. 不想写脚本清理 mongodb 中的垃圾数据,ttlIndex 能帮到你!

    mongodb一直都在不断的更新,不断的发展,那些非常好玩也非常实用的功能都逐步加入到了mongodb中,这不就有了本篇对ttlindex的介绍,刚好我们的生产业务场景中就有一个案例... 一:案例分 ...

  9. 如何在内存中存储有序数据?

    目前有很多种不同的数据结构可以在内存中存储有序的数据.在分布式数据库的存储引擎中,有一种结构因其简单而被广泛地使用,那就是跳表(SkipList). 跳表的优势在于其实现难度比简单的链表高不了多少,但 ...

最新文章

  1. kmeans及模型评估指标_模型评估常用指标
  2. HDU1425简单排序题
  3. webpack教程(一)
  4. 【Python学习教程】推导式与生成器
  5. 怎么在大学当院系负责人呢?一个case study
  6. java中将int类型数据存到数组中
  7. 5分钟让你了解 ZooKeeper 的功能和原理
  8. 使用ABAP事务码STAD分析Asynchronous RFC call性能
  9. 软件测试人员:如何优秀的提Bug?
  10. 什么是RPA 现在都有哪些产品
  11. java replacefirst第n_Java中replace()、replaceFirst()和replaceAll()区别
  12. 课程目标IO java
  13. 举例说明操作系统在计算机系统中的重要地位,第一二三章作业参考答案
  14. python接口自动化(十一)--发送post【data】(详解)
  15. Visual Assist X是个好东西呀
  16. win10安装wireshark经常报“KB2999226 和 KB3118401”补丁未安装的问题
  17. 把显存用在刀刃上!17 种 pytorch 节约显存技巧
  18. 用户路径分析之利器“桑基图”
  19. Python使用正则表达式提取文本中ABAC和AABB形式的成语
  20. Miktex安装宏包

热门文章

  1. 设置 JDK环境变量(Windows)
  2. hibernate左连接查询时在easyUI的dataGrid中有些行取值为空的解决办法
  3. graal java_如何在CircleCI上构建支持Graal的JDK8?
  4. jsr303 spring_使用Spring和JSR 303进行方法参数验证
  5. web前端面试问答_Web服务面试问答
  6. javafx 动画没效果_通过JavaFX标注制作动画效果
  7. java 异常处理发生异常_处理Java中的异常
  8. jax-rs jax-ws_快速浏览JAX-RS请求与方法匹配
  9. 将Auth0 OIDC(OAUTH 2)与授权(组和角色)集成
  10. java常见_关于Java的常见误解