13和14获得年度数据库.https://db-engines.com/en/ranking
官方文档: https://docs.mongodb.com/manual/
简介
MongoDB是面向文档的数据库, 有区别与传统的RDBM, 是一个基于文档(BSON, Binary Json)存储的开源数据库系统, 其主要的大致特性如下:
易用性: MongoDB的文档可以类比RDBMS的行, 通过在文档中嵌入文档, 数组来表达复杂的层次关系,类似编程思想的组合.
易拓展: scale属性, 面对数据的增加, 多节点的存储拓展, 传统的RDBMS的一般自身没有面对海量数据的能力, 而mongodb其内部自身实现了集群的数据与请求的负载分配.(分片)
功能丰富: 支持索引, 聚合, 特殊集合, 文件存储(GridFS), map/reduce, 不支持在分布式架构中性能不佳的join(不需要), 事务(4.0已经支持).
性能卓越: 尽可能保留RDBMS功能的同时追求卓越的性能, 主要体现为cache内存, 动态填充, 预分配数据文件等等.
主要用途
跟RDBMS一样, 可以做应用数据库, 4.0之后支持了ACID事务, 同时模型更加灵活, 因为是BSON格式, 与面向对象十分吻合
海量数据平台, 可以横向扩展, 数据切片存储.
BSON与JSON对比
https://docs.mongodb.com/manual/reference/bson-types/
Bson是一种类Json的一种二进制形式的存储格式,类型比Json要丰富, 空间存储不占优势, 更快的查询速度, 操作简单, 在MongoDB的大小限制是16mb, 每一个document都需要一个_id.
版本进展
2008: 0.x: 起步阶段
2010: 1.x: 支持复制集和分片集.
2012: 2.x: 更丰富的数据库功能, 索引, 聚合等等
2014: 3.x: 真正成熟, 有了自己的数据库引擎
2018: 4.x: 支持了事务.
基础知识
主要有文档, 集合, 数据库, 键id, js shell.
文档: 数据的基本单元, 可以理解为RDBMS的行, 是键值对的有序集, 组织结构类似json, 区别在于mongodb的文档字段是有顺序的.
集合: 数据集合,可以理解为RDBMS的表, 但是集合是动态模式, 内部的文档可以是不同结构的, 但是出于索引的考虑, 最好将同一种结构的文档放到一个集合内, 自行设计相应模式.
比如设计父子结构: blog.posts, blog.authors, 其中blog这个父集合甚至不需要存在, 父子集合可以进行逻辑&物理上的分隔, 十分有用.
- 数据库: 多个集合组成数据库, 每一个mongodb实例可以有多个数据库, 每个数据库的权限相互独立.
保留数据库: admin, local, config. 集合的完全限定名是cms.blog.posts, 其中cms是数据库的名字.
- shell:
mongo
命令即可, 是一个js shell,可以运行简单的数学运算, 以及简单的插入查询,是mongodb客户端.
插入:
db.blog.insert({x:5})
查询:db.blog.findOne()
,或者find(). 更新:db.blog.update(...)
删除:db.blog.remove(...)
- 数据类型: (BSON)基本等同于json, 额外支持一些, 比如日期{"x":new Date()}, 比如对象id{"_id":ObjectId("...")}..etc
ObjectId在集合内唯一标志文档的id,11位int值, 使用不需要管, 会自动生成_id的key, 值的话跟时间戳,机器, pid以及计数器有关的hash值.
> db.blog.insert({x:1})
WriteResult({ "nInserted" : 1 })
db.blog.find()
{ "_id" : ObjectId("5e81c27c40ba929757681642"), "x" : 1 }
db和集合的增删
db不用创建, 直接use,或者insert数据后show dbs
就能看到了
# 删除db
db.dropDatabase()
创建集合options是一个json配置, json Schema
db.createCollection(name, options)
删除集合
db.collection.drop()
json schema是无模式下的规范, https://docs.mongodb.com/manual/reference/operator/query/jsonSchema/
基本操作CRUD
具体语言的操作去看开头的官方文档.
create
insertOne/insertMany/insert
read
find/findOne
简单查询条件: https://www.runoob.com/mongodb/mongodb-query.html
正则匹配支持: db.col.find({title:/^教/}), 以教开头.
$type匹配: 匹配key的类型筛选出来.
$exist可以判断是否有某个key的筛选,
nin则是不连续的范围筛选.
如果只需要返回文档的部分key, 就可以使用0,1来额外标志,
find({"name":"huijia"},{"_id":0,"age":1})
, 只返回agepretty()相当于mysql \G, 美观显示.
limit(int)来限制返回的文档数目
还有skip(int)来跳过指定数量的文档, 默认是0, 可以理解位offset.
还有explain()来进行查询分析.
使用hit({"x":1})来强制使用一个索引, 一般配合explain()使用.
update
主要通过操作符, 第一个参数是find的条件,第二个参数是操作.
db.users.update({"name":"huija"},{"$set":{"xxx":1}})
其中$set是个修改器,
还有$unset删除某个字段,
还有$inc原子增加某个数值,
each给数组append数组, 配合sort, 指定权重, 排序后得到前面指定数量的元素.
push类似, 但是会进行去重后才会插入数组.
$ne是查询的时候, 指定不重复的字段.(相当于mysql group by limit 1)
$pop可以指定key,1表示从数组结尾删,-1表示从数组开头删.
$pull可以删除数组内全部匹配的元素值.
or可以进行查询条件约束, 其余可以百度..(太多), json子字段用'.'拼接
支持正则匹配.
delete
deleteOne/deleteMany
还有个remove, 过时了,可以使用, 不会释放db的空间, 需要
db.repairDatabase()
来回收.
简单实践
# 增加
db.users.insert({"name":"huija","friends":32,"enemies":2})
WriteResult({ "nInserted" : 1 })
改update
db.users.find()
{ "_id" : ObjectId("5e82abb48c7542360d1e5434"), "name" : "huija", "friends" : 32, "enemies" : 2 }
var me=db.users.findOne({"name":"huija"})
me.relationships={"friends":me.friends,"enemies":me.enemies}
{ "friends" : 32, "enemies" : 2 }
delete me.friends
true
delete me.enemies
true
db.users.update({"name":"huija"},me)
查find,findOne
db.users.find({"name":"huija"})
{ "_id" : ObjectId("5e82abb48c7542360d1e5434"), "name" : "huija", "relationships" : { "friends" : 32, "enemies" : 2 } }
删remove,drop
db.users.drop()
true
但是上面的update,基本是整体覆盖, 如果想要针对单个属性,进行原子更新, 可以通过修改器实现.
updateOne, updateMany可以控制update的文档数目(1个或者多个)
_id最好不要自己设置
https://www.jianshu.com/p/9e582b470810 https://www.runoob.com/mongodb/mongodb-objectid.html
相比较MySQL,MongoDB数据库更适合那些读作业较重的任务模型。MongoDB能充分利用机器的内存资源。如果机器的内存资源丰富的话,MongoDB的查询效率会快很多。
在带”id”插入数据的时候,MongoDB的插入效率其实并不高。如果想充分利用MongoDB性能的话,推荐采取不带”id”的插入方式,然后对相关字段作索引来查询。
索引
创建很简单:db.col.createIndex({"title":1,"description":-1})
其中1表示升序, -1表示降序.
https://www.runoob.com/mongodb/mongodb-indexing.html
索引是B树, 需要全部加载进内存.
https://www.runoob.com/mongodb/mongodb-indexing-limitations.html
覆盖索引
mysql的覆盖索引主要是为了不回表, 在mongodb中也是类似, 我们可以 通过指定需要查询的值来达到目的.
db.users.find({gender:"M"},{user_name:1,_id:0})
其中1表示需要查出user_name
, 0表示忽略默认就返回的_id
.
mongodb还支持数组等各种子文档的索引
TTL索引
可以用于删除过期数据, ttl索引只支持在Date()类型单字段建立
当你在集合中某一个字段建立TTL索引后,后台会有一个单线程,通过不断查询(默认60s一次)索引的值来判断document是否有过期,
并且删除文档的动作还依据mongod实例的负载情况,如果负载很高,可能会稍微延后一段时间再删除。
还有一个需要注意的地方,在复制集成员中,TTL后台线程只删除primary的过期数据,如果此实例变为secondary角色,则后台线程闲置
https://blog.csdn.net/leshami/article/details/61195427
聚合
是一个pipeline处理, 指定一些聚合的组合,每一个聚合都是一个stage步骤, 整体作为参数进行聚合操作. db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
https://www.runoob.com/mongodb/mongodb-aggregate.html
聚合框架中常用的几个操作:
$project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。(as)
match使用MongoDB的标准查询操作。(where)
$limit:用来限制MongoDB聚合管道返回的文档数。
$skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
$unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
$group:将集合中的文档分组,可用于统计结果。(group by)
$sort:将输入文档排序后输出。(order by)
$geoNear:输出接近某一地理位置的有序文档。
$lookup: ... (left outer join)
引用
对于Bson的类型, 我们可以类比结构体, 而结构体是可以嵌套组合的, 而Bson如何实现文档的组合呢, 比较Bson是无范式的, 是很灵活的.
使用ObjectID, 类似地址一样, 进行组合.
{
"_id":ObjectId("52ffc33cd85242f436000001"),
"contact": "987654321",
"dob": "01-01-1991",
"name": "Tom Benzamin",
"address_ids": [
ObjectId("52ffc4a5d85242602e000000"),
ObjectId("52ffc4a5d85242602e000001")
]
}
但是这只是文档的直接引用, 如果需要从多个db集合进行引用也是可以的, 具体需要指定一些额外参数.
优势
易于开发者使用, 使用对象模式, 不需要特别多的时间进行建模, 而且不需要维护复杂的关系.
可动态增加新字段, 但是也有一定的规则限制,Json Scheme.
原生的高可用与横向拓展: 副本集, 一主两从, 数据冗余存储, 提高了数据的可用性, 并可以保证数据的安全性。https://www.runoob.com/mongodb/mongodb-replication.html
另一种集群: 数据负载存储,可自定义分片规则.https://www.runoob.com/mongodb/mongodb-sharding.html . https://cloud.tencent.com/developer/article/1453249
副本集可以与分片相结合: https://docs.mongodb.com/manual/tutorial/convert-replica-set-to-replicated-shard-cluster/
工具
mongodb提供了免费的云集群搭建.
图形化软件, 官网提供了compass. https://www.mongodb.com/download-center/compass
demo数据集: https://raw.githubusercontent.com/tapdata/geektime-mongodb-course/master/aggregation/dump.tar.gz ,可以使用
mongorestore
来恢复, 默认当前目录下的mock文件夹, 备份恢复参考: https://www.runoob.com/mongodb/mongodb-mongodump-mongorestore.html
compass可以查看数据, 聚合计算, schema分析, 索引查看, 图形化explain, 制定一些schema约束(哪些key必须有, 哪些key的类型限定等等)
选型总结
如果业务满足一个或多个特点,那么选择MongoDB是个正确的决定:
无需要跨文档或跨表的事务及复杂的join查询支持
敏捷迭代的业务,需求变动频繁,数据模型无法确定
存储的数据格式灵活,不固定,或属于半结构化数据
业务并发访问量大,需数千的QPS
TB级以上的海量数据存储,且数据量不断增加
要求存储的数据持久化、不丢失
需要99.999%的数据高可用性
需要大量的地理位置查询、文本查询