利用“海底捞算法”在MongoDB中优雅地存储一棵树
目前常见的树形结构数据库存储方案有以下四种,但是在处理无限深度、海量数据的树结构时,都存在一些问题:
1)Adjacency List(邻接表):每个节点仅记录父节点主键。优点是简单,缺点是访问子树需要递归遍历,对数据库压力大(即使是支持递归SQL的数据库)。
2)Path Enumerations( 路径枚举):用一个字符串记录当前节点所在路径。优点是查询方便,缺点是占用空间大,查询需要使用like模糊方法,效率低,插入新记录时要手工更改此节点以下所有路径,维护不便。
3)Closure Table(闭包表):专门一张表维护Path,缺点是占用空间大,操作不直观。
4)Nested Sets (嵌套集):记录左值和右值,优点是查询子树无需递归,缺点是非常复杂、难操作。
本文介绍的方案原理详见"基于前序遍历的无递归的树形结构的数据库表设计" ,在这里我给它名叫“海底捞算法”,这个比较形象,因为它要求插入一行EndTag在表格的底部(具有最大行号)。本文是这种算法在MongoDB中的实现示例。
这个算法的优点是简单,支持无限深度树、查询子树时无需递归、删除节点和偶尔插入节点时可以做到无需修改其它记录(行号跳号设计),从以下示例代码中就可以看出这种方案的简洁性:
Books
|-Programning
| |-Languages
| |-Databases
| | |-MongoDB
| | | |-MongoTree
| | |-dbm
|-Arts db.book.insert({ _id: “Books”, line:1000,level:1} );
db.book.insert({ _id: “Programming”, line:2000,level:2} );
db.book.insert({ _id: “Languages”, line:3000,level:3} );
db.book.insert({ _id: “Databases”, line:4000,level:3} );
db.book.insert({ _id: “MongoDB”, line:5000,level:4} );
db.book.insert({ _id: “MongoTree”, line:6000,level:5} );
db.book.insert({ _id: “dbm”, line:7000,level:4} );
db.book.insert({ _id: “Arts”, line:8000,level:2} );
db.book.insert({ _id: “EndTag”, line:10000,level:0} ); //查询节点 “Databases”下的所有子节点:
db.book.createIndex( {line:1});
var node = db.book.findOne( { _id: “Databases” } );
var next=db.book.findOne( { $and: [ {line: {$gt:node.line}}, {level:{$lte: node.level }}] } );
db.book.find( {$and: [{line: { $gt: node.line }}, {line: { $lt: next.line }}] } ); //插入一个新节点,不需要对其它行号执行加1操作,因为这个示例中行号是跳号设计的,节点可以插入在两个行号的中间
db.book.insert({ _id: “MySql”, line:6500,level:5} ); //删除一个节点,真接删就可以了
db.book.remove({ _id: “Languages”} );
利用“海底捞算法”在MongoDB中优雅地存储一棵树的更多相关文章
- MongoDB中空间数据的存储和操作
本文使用官方C# Driver,实现在MongoDB中存储,查询空间数据(矢量) 空间数据的存储 本例中,从一个矢量文件(shapefile格式)中读取矢量要素空间信息以及属性表,并写入到MongoD ...
- MongoDB中如何优雅地删除大量数据
删除大量数据,无论是在哪种数据库中,都是一个普遍性的需求.除了正常的业务需求,我们需要通过这种方式来为数据库"瘦身". 为什么要"瘦身"呢? 表的数据量到达一定 ...
- 浅析mongodb中group分组
这篇文章主要介绍了浅析mongodb中group分组的实现方法及示例,非常的简单实用,有需要的小伙伴可以参考下. group做的聚合有些复杂.先选定分组所依据的键,此后MongoDB就会将集合依据选定 ...
- 机器学习实战 - 读书笔记(07) - 利用AdaBoost元算法提高分类性能
前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习笔记,这次是第7章 - 利用AdaBoost元算法提高分类性能. 核心思想 在使用某个特定的算法是, ...
- 06 - 从Algorithm 算法派生类中删除ExecuteInformation() 和ExecuteData() VTK 6.0 迁移
在先前的vtk中,如vtkPointSetAlgorithm 等算法派生类中定义了虚方法:ExecuteInformation() 和 ExecuteData().这些方法的定义是为了平稳的从VTK4 ...
- mongodb中数据类型的坑
在mongodb中,我们给每个文档插入数据的时候,mongodb自动会为我们插入的数据创建数据类型.由于mongodb是一个非结构化的数据存储系统,因此在文档中你可以随意插入不同类型的字段,这和MyS ...
- KMP算法 --- 在文本中寻找目标字符串
KMP算法 --- 在文本中寻找目标字符串 很多时候,为了在大文本中寻找到自己需要的内容,往往需要搜索关键字.这其中就牵涉到字符串匹配的算法,通过接受文本和关键词参数来返回关键词在文本出现的位置.一般 ...
- MongoDB中的映射,限制记录和记录拼排序 文档的插入查询更新删除操作
映射 在 MongoDB 中,映射(Projection)指的是只选择文档中的必要数据,而非全部数据.如果文档有 5 个字段,而你只需要显示 3 个,则只需选择 3 个字段即可. find() 方法 ...
- MongoDB中聚合工具Aggregate等的介绍与使用
Aggregate是MongoDB提供的众多工具中的比较重要的一个,类似于SQL语句中的GROUP BY.聚合工具可以让开发人员直接使用MongoDB原生的命令操作数据库中的数据,并且按照要求进行聚合 ...
随机推荐
- ZT 第9章 Framework的启动过程
所在位置: 图书 -> 在线试读 -> Android内核剖析 第9章 Framework的启动过程 9.3 zygote的启动 前面小节介绍了Framework的运行环境,以及Dalvi ...
- There was a problem confirming the ssl certificate: [SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:661) - skipping
Could not fetch URL https://pypi.python.org/simple/xlrd/: There was a problem confirming the ssl cer ...
- chrome最新版49跨域问题
chrome最新版49跨域问题 一.最新版49要用新的参数 加--user-data-dirwindows:"C:\Program Files\Google\Chrome\Applica ...
- PhoneGap API 之事件处理
一. deviceready 事件 1.在使用 PhoneGap 开发应用时,deviceready 事件是非常常用的.这一事件在设备的本地 环境和页面完全加载完成之后才触发 2.注意:此事件一般晚于 ...
- 【[USACO12MAR]园林绿化Landscaping】
我旁边有一个暴力的金牌爷整天欺负我嘤嘤嘤 关我电脑,关我浏览器,还钦定我学不会贪心 没错我就是学不会了 这道题还是非常妙的 我们发现这个土的数量实在是少的可怜,于是我们甚至可以对每一个单位的土都进行贪 ...
- gdb tui中切换窗口
gdb的gui用法 调试代码的时候,只能看到下一行,每次使用list非常烦,不知道当前代码的context http://beej.us/guide/bggdb/#compiling 简单来说就是在 ...
- 微服务前端开发框架React-Admin
前言 React-Admin是基于React16.x.Ant Design3.x的管理系统架构. 采用前后端分离,内置了许多管理系统常用功能,通过一些脚本.封装帮助开发人员快速开发管理系统,集中精力处 ...
- ios开发遇到的问题
运行后界面空白,Xcode跳转到APPDelegate.swift文件提示如下 第一种可能原因: 做输出口后在代码中重新命名了输出口 解决方法: 右键控件关闭输出口的连接,变回+号,将它重新连到代码的 ...
- HTML中放置CSS的三种方式和CSS选择器
(一)在HTML中使用CSS样式的方式一般有三种: 1 内联引用 2 内部引用 3 外部引用. 第一种:内联引用(也叫行内引用) 就是把CSS样式直接作用在HTML标签中. <p style ...
- ES6中let与const命令详解
阮一峰ES6入门 let 作用域 let命令用来声明变量,但声明的变量只在let命令所在的代码块内有效. { let a = 10; var b = 1; } a // ReferenceError: ...