一、MongoDB的特点
mongo的特点一图以蔽之:
先说说关系型数据库:
这里的“关系”究竟指的是什么?我们不说大概念和纯理论,只说最实在的东西——关系型数据库中的“表”代表着一类“实体”,实体之间会存在一定关系,比如用户实体和订单实体,一个用户可以有多个订单,而一个订单只属于一个用户,这就是一对多的关系。比如商品和类别,一个商品可以归属多个类别,而一个类别下会有多个商品,这就是多对多的关系。
在关系型数据库中,通过在表中添加存储外键的列来表示这些关系。“主键”阿“外键”阿这些键,本质上就是对一个实体的引用,在一个实体中存储了另一个实体的引用,这样的话,实体之间的关系信息是不是也就有了呢?
这样在查询时,通过主键和外键的关联,就可查询实体与实体间的关系。在修改实体时,由于实体之间的关系仅用引用来表示,所以实体的信息仅存在一处,而引用是不会变的不用修改的,这样也只需修改一处的实体信息即可。
再说说mongo:
mongo的设计目标可不仅仅是简单的键值存储,它也可以做到表达现实世界中纷繁复杂的实体和实体之间的关系,所以它也必须能够处理一对多和多对多的关系,那它是如何做到的呢?
mongo中一个实体由一个文档(document)表示。文档的属性值可以是基本类型和引用,就和RDBMS的表的列的值一样,但与之不同的是,文档的属性值还可以是:
(1)另一个完整的文档而非引用
(2)数组,且数组的元素既可以是基本类型和引用,也可以是一个完整的文档
mongo可以利用文档中的数组,无比直观地表示一对多和多对多的关系。当然也可以像RDBMS那样,在一个文档中存储另一个文档的键来表示这种关系,只不过不能像RDBMS可以通过基于join的连接查询一次查出这种关系,mongo必须经过两次查询(第一次查出符合查询要求的实体,第二次查出与该实体有关系的其它实体)。
同时由于可以值可以是另一个完整的文档而非引用,使其可以设计反范式的数据模型。
二、mongoDB的设计模式
2.1、嵌入与引用
嵌入:包括文档的属性值是一个完整文档,也包括文档的数组属性的元素是一个完整的文档。
引用:就是指文档的属性值是另一个文档id,或文档的数组实行的元素是另一个文档id。
嵌入是反范式的,而引用是符合范式的设计。
嵌入提供了一些查询的性能优势,而引用提供了更多的灵活性。
选择规则:当子文档从不会出现在父文档以外的环境中时使用嵌入方式,否则在单独的集合里存储子文档。
2.2、一对多
(1)像RDBMS那样,在一个文档中存储另一个文档的键来表示这种关系
(2)利用文档的数组,数组的元素是另一个完整的文档
(3)利用文档的数组,数组的元素是另一个文档的id
2.3、多对多
(1)利用文档的数组,数组的元素是另一个文档的id
2.4、树
树的本质是“级联的一对多关系”。要查询树的话,常规做法是递归地进行一对多的查询。树形数据结构并不是mongo所擅长的,但可以通过一种冗余数据的技巧——物化路径的方式,简化树的查询。
遵循物化路径模式,每个树节点都包含一个path字段,这个字段存储了每个级联节点祖先的ID,根节点path为空。
//根节点
{
_id: ObjectId("000");
path: null;
}
//一级节点
{
_id: ObjectId("111");
path: 000;
}
//二级节点
{
_id: ObjectId("222");
path: 000:111;
}
//...
这样在查询特定子树时,比如要查询上述一级节点下的子树,只需 find({path: /^000/}),