简介
NoSQL
NoSQL(非关系数据库)对比MySql等传统关系型数据库的优点是更适合于大规模数据和多种数据的应用场景,尤其是大数据相关问题。NoSQL的应用场景是:
- 对数据库并发读取的需求
- 对海量数据高效率存储和访问的需求
- 对数据库高扩展性和高可用性的需求
传统数据库是通过表、行、列来组织和存储数据的,而NoSQL是用JSON来存储数据。
MongoDb 介绍
MongoDB 是一个介于关系数据库和非关系数据库之间的产品,采用类似json的bson格式来存储数据,因此可以存储比较复杂的类型,这点也是我学习MondgoDB的最大原因,之前编写iot后台处理程序来存储网关上传的传感器数据时使用的是序列化的json作为字符串来存储到mysql中的,因为传感器数据各种各样,无法使用固定的结构,如果使用MongoDB就不会出现这种非规范化的操作了。
MongoDB支持类似面对对象的查询语言,JSON
与js契合度高,而类似JSON
的BSON
类似,所以决定使用nodejs搭配MongoDB来实现第二代iot管理平台的原型,具体另开文章来叙述。
安装
略过,查看官网
环境变量配置
默认安装后,如果要在cmd或者wsl中启动,需要配置MongoDB的环境变量。win10的操作如下:
开始菜单栏搜索“环境变量”,打开后选择高级
标签页,点击环境变量
,选择path,将MongoDB中bin文件夹路径填入其中。如下所示。
打开cmd输入 mongo命令,验证是否成功,成功效果如下:
MongoDB使用
服务端启动
MongoDB数据库是使用文件形式存储的(可以用U盘拷贝走,好神奇),因此必须先新建一个文件夹,用来存放数据库。比如 E:\4.临时文件\mongo_db_dir
,新建完成后可使用mongod命令来啊开启数据库服务:
mongod --dbpath E:\4.临时文件\mongo_db_dir
- mongod 是MongoDB启动命令
- –dbpath是指定数据库文件存放位置,后边是路径
如下:
客户端连接
执行
mongo 127.0.0.1:27017
- mongo 是客户端启动命令
- 127.0.0.1:27017 是MongoDB数据库服务端的IP地址和端口
成功连接的截图如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
数据库操作
查看所有数据库列表
在mongo shell中执行:(本文下面命令均为mongoshell命令)
show dbs
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
创建数据库
MongoDB中集合相当于mysql中的表,文档相当于mysql中的行。
创建数据库和使用数据库是同一个命令
use student
- use 是选择命令(也是新建命令)
- student 是数据库名称
与mysql不同的是,MongoDB数据库创建成功后必须向其中插入一条数据,否则创建失败。
插入数据
而数据库不能直接插入数据,数据只能插入到集合(表)中,使用命令:
db.student.insert({"name":"zhangsan"})
-
db 默认值,代表当前选中的数据库。
-
student 是集合名称。
-
mongoDB中插入的数据是json格式,{“name”:“张三”}是插入的数据。
上述命令执行后,系统发现student没有这个集合,因此自动创建改集合(表)
执行结果:
查看所有集合(表)
查看当前选择数据库中的所有集合,执行:
show collections
删除集合(表)
db.student.drop()
- db 当前选中数据库
- student 要删除的集合名称
- drop() 删除命令
结果如下:
删除数据库
db.dropDatabase();
- dropDatabase() 删除命令
查询数据
1. 查询所有记录
db.user.find() //等同于 select * from user;
- user 是集合名称,(表名称)
- find() 查询操作
2. 过滤某列重复数据
db.user.distinct("name"); //等同于 select distict name from user;
- user 集合名称
- distinct 过滤查询
3. 条件查询
a. 查询 age=27的记录
db.user.find({"age":27}) //等同于 select * from user where age = 27;
b. 查询 age>27的记录
db.user.find({age:{$gt:22}}) //等同于 select* from user where age >22;
- $gt 表示大于
c. 查询 age<27 的记录
db.user.find({age:{$lt:27}}) //等同于 select * from user wwhere age < 27;
- $lt 表示小于
d. 查询 age>= 27 的记录
db.user.find({age:{$gte:27}}) //等同于 select * from user where age >= 27;
- $gte 表示大于等于
- $lte 表示小于等于
e. 查询 age>=23 并且 age<=26 的记录
db.user.find({age:{$gte:23,$lte:26}})
结果如下:
f: 查询name中含有mongo 的数据 (模糊查询用于搜索)
db.user.find({name:/mongo/}) //等同于 select * from user where name like '%mongo%';
- db 当前选择的数据库
- user 集合(表)
- find({name:/mongo/}) 查询集合(表)中name包含mongo的记录,侯彪的//应该是正则
g: 查询name中以iam 开头的金鸡路
db.user.find({name:/^iam/}) //等同于 select * from user where name like `mongo%`;
结果如下:
h:查询指定列 name 和 age 的数据
db.user.find({},{name:1,age:1}); //相当于select name,age from user;
- find({},name:1,age:1) 前一个{} 是搜索条件,后一个{}是显示字段,其中1,亦可以使用true或者false,如果为false,那么就是排除指定字段,显示其他字段。
i: 查询指定列 name,age,并限定age>25
db.user.find({age:{$gt:25},{name:true,age:true}}) //相当于 select name,age from user where age>25;
j: 按照年龄排序 1 升序 -1降序
db.user.find().sort({age:1}) //升序
db.user.find().sort({age:-1}) //降序
k: 查询name=张三,age=22 的数据
db.user.find({name:"zhangsan",age:22}) //等同于 select * from user where name = 'zhangsan' and age = '22';
l: 查询前5条数据
db.user.find().limit(5) //等同于 selecttop 5 * from user;//不确定,,,
m: 查询10条以后的数据
db.user.find().skip(10); //相当于 select * from user where id not in (selecttop 10 * from user) //不确定没试过mysql此条。。
n:查询 5-10 之间的数据
db.user.find().limit(10).skip(5);
这条查询命令可以用于分页,比如limit 是pagesize,skip是第几页*pagesize
比如每页5条,我要查看第三页的数据,那么有
db.user.find().limit(5).skip(10)//5是每页条数,10是2*5,要跳过的条数
o:条件 或 查询 查询age=22或者=29 的记录
db.user.find({$or:[{age:22,{age:29}]}) //等同于 select * from userwhere age=22 or age = 25;
p: 查询第一条数据
db.userinfo.findOne(); //等于于db.userinfo.find().limit(1) //等同于 selecttop 1 * from user;//不确定
q:查询结果集中的总记录条数, 用于统计数量
db.user.find({age:{$gte:25}}).count(); //相当于 select count(*) from userinfo where age>=20;
修改更新数据
a. 更改部分字段(字段不准确,应该是更改部分属性):
db.user.update({name:"liming"},{$set:{age:16}})
- update 更新数据的命令,前一个对象是检索条件,检索name是liming的记录,后一个对象{$set:{age:16}} 要更改为的数据
整个语句的作用是修改属性name为liming的对象中的age为16,执行结果如下:
默认情况下update
操作是匹配单个document(记录)要匹配所有记录,需要在update方法中增加一个{multi:true}对象
db.user.update({sex:"man"},{$set:{age:18}},{multi:true});
b. 如果是对doucment,也就是记录进行完全修改,那么就不能出现$set
关键字了
比如修修改name=lisi的对象所有属性为{name:lisi2,age:100}
db.user.update({name:"lisi"},{name:"lisi2",age:100})
c. 复杂修改,为指定记录的age增加20岁
db.user.update({name:"lisi2"},{$inc:{age:10}},false,true) //这条没有验证成功!
为name等于lisi2的记录 属性age增加10
错误截图
提示没有选中。。为什么???
删除数据
db.user.remove({name:"lisi2"})
- user 集合名称
- remove 删除方法,参数对象是要删除document的检索条件。
注意:与update不同的是remove操作默认将删除所有匹配记录,如果要删除第一个条匹配的记录(document),操作方法中增加{justOne,true}对象
如下:
db.user.remove({name:"lisi2"},{justOne:true});
索引
针对关系型数据库,索引是对数据库表中一列或者多列的值进行排序的一种结构,可以然我们查询数据库变得更快。而MongoDB索引与关系型数据库相似,建立索引也能加快查询速度。
基本命令
为演示索引建立前后的查询速度对比,可以在MongoDB客户端shell中使用js语法创建一个大数据量的集合 teacher。建集合(表)命令如下:
for(var i = 0; i < 655360; i++){
db.teacher.insert({name:"teacher"+ i,age:Math.ceil(Math.random()*100),sex: Math.random()>0.5?"man":"woman"})}
}
运行结果是:(因为要插入65万条数据,数据量大命令执行时间长,耐心等待)
1. explain 工具
explain 命令能够显示查询语句的相关信息,包括查询索引情况、耗时以及扫描文档数等统计信息。
db.teacher.find({name:"teacher456780"}).explain()
这里我们暂时关注查询耗时,用来验证索引加上前后的不同。
db.teacher.find({name:"teacher456780"}).explain("executionStats")
2. 查询索引
db.teacher.getIndexes()
默认只有一个索引:_id,(关注key)
3. 创建索引
db.teacher.ensureIndex({name:1})
- teacher 是创建索引的集合名称
- ensureIndex({name:1}) ensureIndex是创建索引命令,name是 要创建索引的属性(字段)其中1表示对name进行升序排序,-1 表示对name进行降序排序
索引创建成功。
4. 删除索引
db.teacher.dropIndex({name:1})
5. 验证索引作用
为了验证索引对于查询速度的作用,可以在teacher集合中根据name属性查询一条记录,记录查询时间,然后为name建立索引后再次查询,记录插叙时间,对比两者查询时间。
未建立索引查询截图
建立索引后查询截图
可以看出未对name属性建立索引对name属性进行查询时耗时968ms,而建立后仅仅耗时3ms,因此来看索引加快查询速度是真的!
6. 复合索引
符合索引是多一个集合中多个属性(一个表中多个字段)同时建立索引,比如:
db.teacher.ensureIndex({name:1,age:-1})
- 为teacher集合建立name与age的符合索引,name升序排列,age降序排列。
复合索引创建后,对name与age的查询会用到索引,另外对于前一个name的查询,也会要到,但是对age的查询就不可以了。所以要使用符合索引,必须在查询条件中包括符合索引的前N个索引属性,最后一个索引属性不能用。
可以看出对符合索引中前n个(1)字段name索引,可以使用符合索引,加快查询速度,对符合索引最后一个字段age进行查询,不能使用符合索引,所以耗时仍然与未建立索引保持一致,耗时时间长。
注意:对大数据量的集合中的无索引元素进行排序时,需要把所有数据提取到内存中,有可能导致爆内存,导致MongoDB报错。
7. 唯一索引
唯一索引的作用是保证集合(表)中对建立索引的字段保证唯一性,比如对id建立唯一索引,那么这个集合就不可以出现相同id的document(记录)。默认创建的索引不是唯一索引,建立唯一索引的命令如下:
db.user.ensureIndex({name:1},{unique:true})
- unique:true 表示建立唯一索引
唯一索引建立后,再次插入相同内容的name属性会报错。
如果插入新的document(记录)不包含唯一索引字段时,MongDB默认将其置为null,如果多次插入相同的内容,null也会受到唯一索引限制,报错。
对于一个没有建立唯一索引,但是存在字段数据重复的document(记录)时,建立唯一索引会报错
符合索引也可以建立唯一索引
db.teacher.ensureIndex({name:1,age:-1},{unique:true})
8.索引操作相关参数
查看数据库大小
1,查看数据库
db.stats();
各项含义
{
“db” : “test”, //当前数据库
“collections” : 3, //当前数据库多少表
“objects” : 4, //当前数据库所有表多少条数据
“avgObjSize” : 51, //每条数据的平均大小
“dataSize” : 204, //所有数据的总大小
“storageSize” : 16384, //所有数据占的磁盘大小
“numExtents” : 3,
“indexes” : 1, //索引数
“indexSize” : 8176, //索引大小
“fileSize” : 201326592, //预分配给数据库的文件大小
“nsSizeMB” : 16,
“dataFileVersion” : {
“major” : 4,
“minor” : 5
},
“ok” : 1
}
2,查看数据库表
db.datapoint_histories.stats();
主要参数如下:
{
“ns” : “test.posts”,
“count” : 1,
“size” : 56,
“avgObjSize” : 56,
“storageSize” : 8192,
“numExtents” : 1,
“nindexes” : 1,
“lastExtentSize” : 8192,
“paddingFactor” : 1,
“systemFlags” : 1,
“userFlags” : 0,
“totalIndexSize” : 8176,
“indexSizes” : {
“id” : 8176
},
“ok” : 1
}