MongoDB是跨平台,面向文档的数据库,提供高性能、高可用、易拓展,是工作在集合和文档上的概念。是非关系型数据库,NOSQL的含义是not only sql,不仅仅是数据库。
关系型数据库中的表都是存储一些结构化的数据,每条记录的字段的组成都一样,即使不是每条记录都需要所有的字段,但数据库会为每条数据分配所有的字段。而非关系型数据库以键值对(key-value)存储,它的结构不固定,每一条记录可以有不一样的键,每条记录可以根据需要增加一些自己的键值对,这样就不会局限于固定的结构,可以减少一些时间和空间的开销。
常见的NoSql(非关系型数据库)数据库
CouchDB
Redis
MongoDB
Neo4j
HBase
BigTable
NoSql数据库优缺点
在优势方面主要体现在下面几点:- 简单的扩展
快速的读写
低廉的成本
灵活的数据模型
在不足方面主要有下面几点:
不提供对SQL的支持
支持的特性不够丰富
现有的产品不够成熟
MongoDB简介
MongoDB是用C++语言编写的非关系型数据库。特点是高性能、易部署、易使用,存储数据十分方便,主要特性有:
面向集合存储,易于存储对象类型的数据
模式自由
支持动态查询
支持完全索引,包含内部对象
支持复制和故障恢复
使用高效的二进制数据存储,包括大型对象
文件存储格式为BSON(一种JSON的扩展)
MongoDB基本概念
文档(document)是MongoDB中数据的基本单元,非常类似于关系型数据库系统中的行(但是比行要复杂的多)。
集合(collection)就是一组文档,如果说MongoDB中的文档类似于关系型数据库中的行,那么集合就如同表。
MongoDB的单个计算机可以容纳多个独立的数据库,每一个数据库都有自己的集合和权限。
MongoDB自带简洁但功能强大的JavaScript shell,这个工具对于管理MongoDB实例和操作数据作用非常大。
每一个文档都有一个特殊的键”_id”,它在文档所处的集合中是唯一的,相当于关系数据库中的表的主键。
MongoDB安装启动
安装mongodb后,dos进入mongodb根目录的bin目录下,启动mongodb服务,命令为mongod.exe --dbpath "d:\mongo\data",
使用参数--dbpath,指定mongodb的数据目录。之后dos界面会输出一些启动信息,表示启动成功。
进入mongodb操作界面,dos进入到bin路径下,执行mongo.exe,就进入了mongodb的操作界面。
MongoDB常用命令
db 显示当前所在的数据库
db.version();查询mongodb数据库版本
use dbone 切换到数据库dbone,如果数据库dbone不存在的话,那么就会自动创建数据库dbone,如果新创建的数据,没有插入数据的话,使用show dbs,是不会显示刚刚创建的数据库。
show dbs 显示所有数据库
db.createCollection("c1") 创建集合c1
db.dropDatabase()删除当前数据库
show tables、show collections 显示当前数据库的集合
db.tuser.drop() 删除tuser集合
db.createCollection("tab1",{capped:true,autoIndexId:true,size:6142800,max:1000}) 创建集合tab1,第二个参数options是可选的。
db.tab1.insert({"a":1}) 向tab1集合中插入数据,如果集合tab1不存在的话,就会创建tab1集合。
mongodb存储的字符串必须是UTF-8
mongodb集合中插入文档的方法用insert()或者save()。mongodb插入的文档,若不指定_id,则会自动分配一个唯一的ObjectId。
如果指定_id,则将以save()方法的形式替换包含_id的文档的全部数据。
db.col1.insertOne()单个文档插入集合
db.col1.insertMany() 将多个文档插入到集合中
db.col1.find() 查找col1集合里的数据
db.col1.find().pretty()查找col1集合里的数据,并格式化显示
db.col1.find({$and:[{"c":3},{"d":5}]}) 查找c="3" and d="5"的数据
db.col1.find({$or:[{"c":3},{"d":5}]}) 查询c="3" or d="5"的数据
db.col1.find({"c":5,$or:[{"d":"5"}]}) 查找c="5" and d="5"的数据,这里两个条件是与的关系
db.col1.find({"k":/^here/}) 相当于sql:select * from col1 where k like "here%"
相等 {<key>:<value>}
小于{<key>:{$lt:<value>}}
小于等于{<key>:{$lte:<value>}}
大于{<key>:{$gt:<value>}}
大于等于{<key>:{$gte:<value>}}
不等于{<key>:{$ne:<value>}}
db.col1.find({k1:{$ne:5}}) 查找k1!=5的数据,没有k1属性的数据也会被查找出来
db.co1.find({k1:{$gt:6}}) 查找k1>6的数据,没有k1属性的数据不会被查询出来,只有上面$ne条件才会被一起查询出来
嵌套查询
集合col1中有一条数据为{"id":ObjectId("5abck123idkekauc98"),"k":66,"v":{"a":99,"b":"cc0"}}
db.col1.find({"v.a":99}) 这条数据中嵌套了一个对象v,v的属性有a=99的数据,这里的v.a要用双引号包括,若为db.col1.find({v.a:99})这样会报错。若为db.col1.find({k:66})和db.col1.find({"k":66})是一样的,不会报错。
mongoDB的update()和save()方法用于将集合中的文档更新。update()方法更新现有文档中的值,而save()方法使用save方法中传递的文档数据替换现有文档。
db.col1.update({"k":5},{$set:{"k3":"update ok","k4":false}}) 这个语句相当于update col1 set k3="update ok",k4=false where k=5 ,mongoDB 只会更新一个文档,要更新多个文档,需要加上multi参数,将multi设置为true。
db.col1.update({"k":5},{"k3":"update ok","k4":false},{"multi":true})
mongoDB save 方法中传递的文档数据替换现有文档。save 若有加唯一标识_id,如果_id存在,则更新,不存在则保持。
remove()方法用于从集合中删除文档。remove方法接收2个参数,一个是删除条件,一个是标志:justOne(可选参数,若设置true或者1,则只删除一个文档)
db.col1.remove({"k":"2"})删除k="2"的数据
db.col1.remove({"k":"2"},1) 删除k="2"的一条数据
投影
mongoDB的投影的意思是指仅选择所需要的数据字段,而不是选择整个文档字段的数据,也就是sql中的select a,b,c from t 从表t选择a,b,c字段
为了限制显示的字段,需要将字段列表对应的值设置为1或者0,1用于显示字段,而0用于隐蔽字段。
db.col1.find({},{"title":1,"_id":0,"name":1}) 查找集合col1中筛选出字段title,_id,name字段的文档,并隐蔽了_id字段,_id默认是不隐蔽的。若是_id也设置为0,且文档中也无title和name字段,那么查询出的结果,会以{}这样的空数据显示。
限制查询结果条数
要限制mongoDB中返回的文档数,需要用到limit()方法,该方法接受一个数字类型参数,它是要显示的文档条数。
db.tab.find().limit(5) 将查询文档结果限制5条。除了limit()外,还有skip()可以接受数字参数,用于跳过文档数量。
db.tab.find().limit(2).skip(1) 和 db.tab.find().skip(1).limit(2)是一样的意思。假设db.tab.find()查询的数据是1,2,3,4,5,那么刚刚的查询语句2,3 。可以认为把limit()方法,放到最后执行。
排序文档
mongoDB排序文档,需要用到sort方法,该方法可以接受包含列表及其排序顺序的文档。使用指定排序顺序1和-1。1用于升序,-1用于降序。
db.tab.find({},{"key":1,"value":-1,"_id":0}).sort({"key":1}),查询出key和value字段的文档列表,按key升序排序显示。
创建索引
db.tab.ensureIndex({"title":1}),在字段title上面创建索引,也可以在多个字段上面创建索引。
聚合查询
聚合操作处理数据记录并返回计算结果。聚合操作将多个文档的值组合在一起,并可对分组数据执行各种操作,以返回单个结果。对应mongoDB中的聚合,应该使用aggregate()方法
$sum 从集合中所有文档中求出定义的值
$avg 计算出集合中所有文档的所有给定值的平均值
$min 从集合的所有文档中获取相应的最小值
$max 从集合的所有文档中获取相应的最大值
$push 将值插入到生成的文档数组中
$addToSet 将值插入生成的文档中的数组,但是不会创建重复项
$first 根据分组从源文档中获取第一个文档,通常情况下,这只适用于以前的应用$sort阶段
$last 根据分组从源文档中获取最后一个文档,通常情况下,这只使用以前的$sort阶段
mongoDB复制
复制是跨多个服务器同步数据的过程,复制提供冗余,并通过不同数据库服务器上的多个数据副本增加数据可用性,备份容灾
mongoDB的分片
分片是在多台机器中之间存储数据记录的过程,满足数据增长的方法,解决了水平缩放的问题。
mongoDB备份恢复
dos进入mongoDB的bin目录下,执行mongodump或者mongodump.exe,会在bin目录下,创建dump文件,这个里面就是备份数据。
恢复数据:mongorestore或者mongorestore.exe,也是进入bin目录执行,会恢复备份目录下的文件
mongostat或者mongostat.exe,也在bin目录下,用于检查所有运行的mongodb实例的状态
mongostop:跟踪并报告基于集合的mongoDB实例的读写活动。
================================================================================================
1、一个文档引用其他多个文档,比如设计一个数据库中将不同类型的地址(家,公司,邮件地址等)存储在不同集合中(add_home,add_office,add_mail等)中。现在当用户集合的文档引用地址时,还需要根据地址类型指定要查找的集合。在这种情况下,文档引用了多个集合中的文档,则应用使用DBRefs。
DBRefs中有3个字段,第一个是$ref:指定引用文档的集合。第二个$id:指定引用文档的_id字段。第三个$db:可选字段,并包含引用文档所在的数据库名称。
2、mongoDB的关联关系有1:1,1:N,N:1,N:N。假设要存储用户的地址,一个用户可以拥有多个地址,这就是1:N的关系。
3、mongoDB的覆盖查询是一个查询,其中查询中所有字段都是索引的一部分,查询中返回的字段都可以在同一个索引中。
db.users.ensureIndex({gender:1,username:1})在gender,user_name创建索引。现在创建索引将覆盖以下查询:
db.users.find({gender:"M"},{user_name:1,_id:0}),对于这个查询mongodb不会查询集合中的数据,相反,它将从索引数据中获取数据,减少对数据库数据的访问。
若是db.users.find({gender:"M"},{user_name:1}) 若是以下这种情况,则无索引覆盖查询。任何索引的字段是一个数组,任何索引的字段是一个子文档。
4、explain() 提供查询的信息,查询中使用的索引和其他统计信息
5、mongodb是不支持多文档事务的。但是它可以为单个文档提供了原子操作。因此,如果文档中有一百多个字段,则更新语句将更新或者不更新所有字段的值,因此在原始级别保持原子性。
维持原子性的推荐方法是将所有相关信息保持在一起,并使用嵌入式文档在一个文档中一起更新。这将确保单个文档的所有更新都是原子的。
6、假设address有city、province、pincode等字段,现在创建索引子文档字段,在子文档的所有字段上创建一个索引。
db.users.ensureIndex({"address.city":1,"address.province":1,"address.pincode":1})。创建索引后,就可以引用此索引来搜索任何子文档的字段。
比如 db.users.find({"address.city":"Haikou"})
7、每个索引都会占用一些空间,并导致每次插入、更新和删除的开销。因此,如果很少使用集合进行读取(大部分是插入或更新操作),建议不要使用索引。
RAM的内存使用,由于索引存储在RAM中,因为应确保索引的总大小不超过RAM限制。如果总大小超过了系统内存的大小,mongoDB将开始删除一些索引,从而导致性能下降。
索引最大范围:集合索引不能超过64个,索引的名称长度不能超过125个字符,复合到最多可以编号31个字段。
8、mongoDB的对象标识符ObjectId,ObjectId是以下具有12字节的BSON类型。前4个字节表示从unix纪元开始的秒数。接下来3个字节是机器标识符,接下来2个字节由进程ID组成,最后3个字节是随机计数器值。
9、GridFS是用于存储技术和检索大型文件,如图像、音频、视频的mongoDB规范。