
NoSQL | Exercises for Chap 4 – Document Databases
NoSQL数据库的四大分类表格分析
分类 | Examples举例 | 典型应用场景 | 数据模型 | 优点 | 缺点 |
键值(key-value)[3] | Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB | 内容缓存,主要用于处理大量数据的高访问负载,也用于一些日志系统等等。[3] | Key 指向 Value 的键值对,通常用hash table来实现[3] | 查找速度快 | 数据无结构化,通常只被当作字符串或者二进制数据[3] |
列存储数据库[3] | Cassandra, HBase, Riak | 分布式的文件系统 | 以列簇式存储,将同一列数据存在一起 | 查找速度快,可扩展性强,更容易进行分布式扩展 | 功能相对局限 |
文档型数据库[3] | CouchDB, MongoDb | Web应用(与Key-Value类似,Value是结构化的,不同的是数据库能够了解Value的内容) | Key-Value对应的键值对,Value为结构化数据 | 数据结构要求不严格,表结构可变,不需要像关系型数据库一样需要预先定义表结构 | 查询性能不高,而且缺乏统一的查询语法。 |
图形(Graph)数据库[3] | Neo4J, InfoGrid, Infinite Graph | 社交网络,推荐系统等。专注于构建关系图谱 | 图结构 | 利用图结构相关算法。比如最短路径寻址,N度关系查找等 | 很多时候需要对整个图做计算才能得出需要的信息,而且这种结构不太好做分布式的集群方案。[3] |
参考:https://blog.csdn.net/cangchen/article/details/44830087
文档数据库与传统的关系数据库差异显著。
关系数据库通常将数据存储在相互独立的表中,这些表由程序开发者定义,一个单一的对象可能散布在若干表中。 对于一个给定对象,文档数据库将其所有信息存储在数据库内某个单一实例中,并且存储的每一个对象可以不同于任一其它对象。这简化了将对象装加载数据库的过程,通常能消除对对象关系映射等类似方案的需求。
文档数据库不同于关系数据库,关系数据库基于了关系模型,而文档数据库采用了半结构化模型,没有在数据和模式(schema)之间的分离,使用的结构的数量依赖于目标用途。在半结构化数据中,属于相同类的实体可有不同的属性,即使它们被分组在一起,并且属性的次序是不重要的。
MongoDB表示文档数据之间关系的设计方法:
一、文档之间通过_id引用的方式关联
-
文档可嵌套——子文档
-
大文档分解 1 :
- 经常访问的field
-
不经常访问的field
- 经常访问的field
-
大文档分解 2 :
首先”1对多”,再”分类”
- product collection ( including recent 10 reviews )
-
review collection
- product collection ( including recent 10 reviews )
-
对于 各个文档都有若干个相同的key-value 的情况:
文档引用
-
方法1 :publisher文档引用book文档
问题:数据长度变化
-
方法2 :book文档引用publisher文档
问题:避免 数据长度变化
-
-
时序文档数据模型设计:
The Bucket Pattern 分桶优化模式 “分组”
时序文档:各个文档都有若干个相同结构的key-value,但是“时间”不同
二、DBRef,可以跨库关联相关文档
参考:https://www.runoob.com/mongodb/mongodb-relationships.html
MongoDB 关系
MongoDB 的关系表示多个文档之间在逻辑上的相互联系。
文档间可以通过嵌入和引用来建立联系。
MongoDB 中的关系可以是:
- 1:1 (1对1)
- 1: N (1对多)
- N: 1 (多对1)
-
N: N (多对多)
接下来我们来考虑下用户与用户地址的关系。
一个用户可以有多个地址,所以是一对多的关系。
以下是 user 文档的简单结构:
{
“_id”:ObjectId(“52ffc33cd85242f436000001”),
“name”: “Tom Hanks”,
“contact”: “987654321”,
“dob”: “01-01-1991”
}
以下是 address 文档的简单结构:
{
“_id”:ObjectId(“52ffc4a5d85242602e000000”),
“building”: “22 A, Indiana Apt”,
“pincode”: 123456,
“city”: “Los Angeles”,
“state”: “California”
}
嵌入式关系
使用嵌入式方法,我们可以把用户地址嵌入到用户的文档中:
{
“_id”:ObjectId(“52ffc33cd85242f436000001”),
“contact”: “987654321”,
“dob”: “01-01-1991”,
“name”: “Tom Benzamin”,
“address”: [
{
“building”: “22 A, Indiana Apt”,
“pincode”: 123456,
“city”: “Los Angeles”,
“state”: “California”
},
{
“building”: “170 A, Acropolis Apt”,
“pincode”: 456789,
“city”: “Chicago”,
“state”: “Illinois”
}]
}
以上数据保存在单一的文档中,可以比较容易的获取和维护数据。 你可以这样查询用户的地址:
>db.users.findOne({“name”:“Tom Benzamin”},{“address”:1})
注意:以上查询中 db 和 users 表示数据库和集合。
这种数据结构的缺点是,如果用户和用户地址在不断增加,数据量不断变大,会影响读写性能。
引用式关系
引用式关系是设计数据库时经常用到的方法,这种方法把用户数据文档和用户地址数据文档分开,通过引用文档的 id 字段来建立关系。
{
“_id”:ObjectId(“52ffc33cd85242f436000001”),
“contact”: “987654321”,
“dob”: “01-01-1991”,
“name”: “Tom Benzamin”,
“address_ids”: [
ObjectId(“52ffc4a5d85242602e000000”),
ObjectId(“52ffc4a5d85242602e000001”)
]
}
以上实例中,用户文档的 address_ids 字段包含用户地址的对象id(ObjectId)数组。
我们可以读取这些用户地址的对象id(ObjectId)来获取用户的详细地址信息。
这种方法需要两次查询,第一次查询用户地址的对象id(ObjectId),第二次通过查询的id获取用户的详细地址信息。
>var result = db.users.findOne({“name”:“Tom Benzamin”},{“address_ids”:1})
>var addresses = db.address.find({“_id”:{“$in”:result[“address_ids”]}})
参考:Mongodb架构设计浅谈
https://juejin.im/post/5a0e370cf265da430d579392
//movie_collection
{
“_id”: 1,
“title”: “哪吒之魔童降世“,
“year”: 2019,
“running_time”: “110 min”,
“released”: [ {“date”: ISODate(“2019-07-26”), “loc”: “中国大陆“},
{“date”: ISODate(“2019-07-13”), “loc”: “大规模点映“} ],
“type”: “movie”,
“directors”: “饺子“,
“scriptwriter“: [“饺子“, “易巧“, “魏芸芸“],
“main_cast”: [“吕艳婷“, “囧森瑟夫“, “翰墨“, “陈浩“, “绿绮“],
“genres”: [“Drama”, “Comedy”, “Cartoon”, “Fantasy”],
“producer_loc”: “China mainland”,
“language”: “Mandarin”,
“alias”: [“哪吒降世“, “Ne Zha”, “Nezha: Birth of the Demon Child”]
}
//movie_details_collection
{
“_id”: 155,
“movie_id”: 1,
“poster”: “http://….jpg“,
“plot”: “天地灵气孕育出……“,
“IMDb_link”: “tt10627720”,
“douban”: {“rating”: 8.6, “num_reviews”: 926892,
“5_stars”: “47.7%”, “4_stars”: “37.5%”, “3_stars”: “12.6%”,
“2_stars”: “1.7%”, “1_star”: “0.6%”,
“better_than_cartoons”: “89%”, “better_than_comedies”: “96%”}
}