利用“海底捞算法”在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原生的命令操作数据库中的数据,并且按照要求进行聚合 ...
随机推荐
- ArcGIS的网络分析
ArcGIS的网络分析分为两类:传输网络(Network Analyst)和效用网络(Utility Network Analyst). 一.从应用上来考虑: 1.传输网络常用于道路.地铁等交通网络分 ...
- 深入浅出SharePoint2013——常用术语
CAS(Code Access Security)自定义代码访问安全性 Sandboxed solution 沙箱解决方案
- POJ 2528 Mayor's poster
主要是参考了这个博客 地址戳这儿 题目大意:n(n<=10000) 个人依次贴海报,给出每张海报所贴的范围li,ri(1<=li<=ri<=10000000) .求出最后还能看 ...
- Git commit comment 汇总标准
参考汇总互联网其它文章建议,结合PEP 257 Docstring Conventions的描述,总结的Git 注释风格,作为个人执行的标准.内容如下: 遵循标准: 1,所有注释尽量坚持使用英文,如果 ...
- Math Summary 数论总结
一.素数 Miller-Rabin 首先介绍一下伪素数:若n是一个正整数,且存在正整数a满足$a^{n-1}\equiv1\;(mod\;n)$ (费马小定理,但n不一定为素数) 那么我们说n是基于a ...
- 【luogu P1879 [USACO06NOV]玉米田Corn Fields】 题解
题目链接:https://www.luogu.org/problemnew/show/P1879 状压DP. 设dp[i][j]表示第i行,状态为j的方案数 初始dp[0][0] = 1 这样一共12 ...
- 获取 当前显示的 UIViewController
UIViewController * findBestVC(UIViewController *vc) { if (vc.presentedViewController) { return findB ...
- JNI由浅入深_7_c调用Java方法一
1.在Java中声明方法 <span style="font-size:14px;">/** * javah -encoding utf-8 -jni com.exam ...
- jfinal form表单提交文件
前台代码 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8&q ...
- 算法的泛化过程(摘自《STL源码剖析》)
将一个叙述完整的算法转化为程序代码,不是什么难事.然而,如何将算法独立与其所处理的数据结构之外,不受数据结构的羁绊呢?换个说法,如何将我们所写的程序算法适用于任何(或者大部分)未知的数据结构(比如ar ...