一、mongodb的概述
1、概述
(1)MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
SQL和NoSQL的主要区别:
● 在SQL中的层级关系是:数据库->表->数据
● 在NoSQL中层级关系是:数据库->集合->数据
(2)为什么要学习它?
- 企业需求(要求爬虫开发工程师必须会这个)
- 大数据量: nosql数据库都具有非常高的读写性能,尤其在大数量下表现优秀
- scrapy_redis适用性小(并不是所有的公司都要用分布式)
(3)mongodb的特点?
a、无数据结构(方便做爬虫)
b、高性能(具有非常高的读写性能)
c、良好的支持(完善的文档 、跨平台、稳定)
2、安装
(1)下载安装包:Mongodb32位的安装程序包地址http://downloads.mongodb.org/win32/mongodb-win32-i386-3.2.4-signed.msi
(2)提前创建好,安装路径文件:(C盘空间不够,就装到D盘)
D:\Program Files\MongoDB\Server\3.2
安装时,选择这个安装路径。
(3)安装完成后,在D盘根目录下创建data/db(这就是未来存放数据的地方)
(4)然后在mongodb的安装目录下(D:\Program Files\MongoDB\Server\3.2\bin),进入cmd。然后输入mongod -dbpath D:\data查看是否连接成功(即是否连接上端口号27017),
上图就是连接失败,此时在安装路径下的bin(D:\Program Files\MongoDB\Server\3.2\bin),进入cmd。执行mongod.exe -dbpath D:\data -storageEngine=mmapv1,执行完后如果出现下图,则表示连接成功。(如果这段语句也不管有,那就在data/db文件中把mongod.lock文件删除后,再运行该段语句)
(5)为了启动mongodb方便,将mongod.exe路径(D:\Program Files\MongoDB\Server\3.2\bin)加入环境变量,电脑->属性->高级系统设置->环境变量,在path里加入路径。这样在命令行任何地方都能用到mongod命令。
3、启动
mongod.exe -dbpath D:\data
结果:
保持上图窗口打开状态,
看到版本号,就是成功了。
我们也可以验证下,输入一个Mongo命令,如下图,并得到结果。
二、基本命令
1、MongoDB三元素(数据库、集合、文档)
文档:就是关系型数据库中的一行。文档是一个对象,由键值对构成,是json的扩展形式。
{"name": "abc", "gender": 1}
集合:就是关系型数据库中的表。可以存储多个文档,结构可以不固定。
{"name": "abc", "gender": 1}
{"name": "abc", "age": 18}
{"title": "abc", "price": 1}
2、MongoDB的数据类型
String:字符串,必须是有效的UTF-8
Boolean:存储一个布尔值,true或者false
Integer:整数可以是32位或64位,这取决于服务器
Double:存储浮点数
Arrays:数组或列表
Object:嵌入式文档
Null:存储Null值
Timestamp:时间戳, 表示从1970-1-1到现在的总秒数
Object ID是一个12字节的十六进制数
3、数据库命名规范
(1).不能是空字符串
(2).不得含有特殊字符
(3).应全部小写
(4).最多64个字节
(5).数据库名不能与现有系统保留库同名,如admin,local
4、基本命令
show dbs :展示数据库
cls :清屏
use demo :使用数据库/创建数据库(demo是我们自定义的数据库名称)
db :查看现在用的数据库
show collections / show tables : 查看当前使用数据库的集合(表)
db.demo.dropDatabase():删除数据库(demo是数据库名称)
(1)插入数据
不手动创建集合的方法:向不存在的集合中第一次加入数据时,集合会被创建出来。例如:db.jerry.insert({x:1})
手动创建集合 : db.createCollection(name,options)
● name: 要创建的集合名称
● options: 可选参数, 指定有关内存大小及索引的选项
db.createCollection('sub',{capped:true,size:10})
db.createCollection('jerry_collection') #参数不写就是默认没有限制
● 参数capped:默认值为false表示不设置上限,值为true表示设置上限
● 参数size:当capped值为true时,需要制定此参数。表示上限大小,当文档达到上限时,会将之前的数据覆盖,单位为字节。如果设置的大小小于256就默认是256。
db.jerry1.isCapped() :返回值fasle没有上限 ,true有上限
db.jerry_collection.drop() :删除表jerry_collection
插入多条数据:
`db.jerry2.insert([{name:'jerry',age:18,gender:'male'},{name:'juran'}])`
for(i=3;i<10;i++)db.jerry3.insert({x:i})
指定了id:就找到这条记录做更新,没有找到或没有指定就插入
db.jerry3.save({_id:ObjectId("60d08f386bd683f7c417e0ac"),name:'jerry',gengder:'male'})
db.jerry3.save({name:'jerry',gender:'male'})
(2)查询数据
以stu为例:
db.stu.insert([{"name" : "张三", "hometown" : "长沙", "age" : 20, "gender" : true },
{"name" : "老李", "hometown" : "广州", "age" : 18, "gender" : false },
{"name" : "王麻子", "hometown" : "北京", "age" : 18, "gender" : false },
{"name" : "刘六", "hometown" : "深圳", "age" : 40, "gender" : true },
{"name" : "jerry", "hometown" : "长沙", "age" : 16, "gender" : true },
{"name" : "小永", "hometown" : "广州", "age" : 45, "gender" : true },
{"name" : "老amy", "hometown" : "衡阳", "age" : 18, "gender" : true }])
db.stu.find() 查询数据/可以在括号里面精确查找
db.stu.find({name:‘jerry’}).pretty() #pretty():将结格式化
db.stu.find({age:18})查询age等于18的数据
db.stu.findOne({age:18}) 把满足结果的第一条数据返回
db.stu.find({age:18,hometown:‘衡阳’}) 多个条件查找
db.stu.find({age:{$gt:18}}) 年龄大于18
db.stu.find({age:{$gte:18}}) 年龄大于等于18
db.stu.find({age:{$gt:18},hometown:'长沙'}) 查找年龄大于18岁并且家乡是长沙的
db.stu.find({$or:[{age:{$gt:18}},{gender:false}]}) 查询年龄大于18或者性别为false
自定义查询:
mongo shell 是一个js的执行环境,使用$where 写一个函数, 返回满足条件的数据
db.stu.find({$where:function(){return this.age>18}})定义方法查询 年龄大于18
(3)操作查询结果
db.stu.find({age:18}).count() :返回查询结果的数量
limit用于读取指定数量的文档,skip用于跳过指定数量的文档:
db.stu.find().skip(2).limit(2) :先跳过2条数据 ,再返回满足结果的前2条数据
映射:指定返回的字段,如果为1则返回该字段,如果为0则除了该字段外所有字段返回。id如果没写会默认返回。映射主key(id) 需要_id:0(就是不返回id)
db.jerry_collection.find({},{_id:1})
排序:
db.stu.find().sort({age:1}) 按照年龄升序
db.stu.find().sort({age:-1}) 按照年龄降序
(4)修改数据
db.集合名称.update({query}, {update}, {multi: boolean})
● 参数query:查询条件
● 参数update:更新的内容
● 参数multi:可选,默认是false,表示只更新找到的第一条数据,值为true表示把满足条件的数据全部更新
db.stu.update({name:'jerry'},{name:'abc'}) 正常的更新,但是后面的数据不会保留
db.stu.update({name:'张三'},{$set:{name:'zhangsan'}}) 指定键值的更新 保留后面的数据
db.stu.update({},{$set:{gender:0}},{multi:true})
db.jerry_collection.update({y:100},{y:101},true)如果y:100数据不存在,就插入y:101这条数据,第三个参数为true
(5)删除数据
db.stu.remove({age:18},{justOne:true}) 删除符合条件的第1个数据
db.stu.remove({age:18},{justTwo:true})删除符合条件的前2个数据
db.jerry_collection.remove() 删除所有数据,索引不会删除
(6)创建索引,默认情况下_id是集合的索引
如何优化
1 常用的一些数据结构和算法
2 尽量减少循环的次数
3 设计模式
4 优秀框架
创建索引就是增加查询效率
创建索引前:
db.test.find({name:'test9999'}).explain('executionStats') # 显示查询操作的详细信息,比如用时
db.test.getIndexes() 查看索引
●创建索引: db.集合名.ensureIndex({属性:1}),1表示升序, -1表示降序
db.test.ensureIndex({name:1}) 创建索引
● 删除索引:db.集合名.dropIndex({‘索引名称’:1})
db.test.dropIndex({name:1}) 删除索引
(7)常用的管道
$group:将集合中的文档分组,可用于统计结果
$match:过滤数据,只输出符合条件的文档
$sort:将输入文档排序后输出
$limit:限制聚合管道返回的文档书
$skip:跳过指定数量的文档,并返回余下的文档
按照gender分组,获取不同组的平均年龄
db.students.aggregate({$group:{_id:'$gender',count:{$sum:1},avg_age:{$avg:"$age"}}})
查询年龄大于20的学生
db.students.aggregate({$match:{age:{$gt:20}}})
查询年龄大于20的男生,女生人数
db.students.aggregate({$match:{age:{$gt:20}}},{$group:{_id:'$gender',count:{$sum:1}}})
(8)常用表达式
$sum: 计算总和, $sum:1 表示以⼀倍计数
$avg: 计算平均值
$min: 获取最⼩值
$max: 获取最⼤值
$push: 在结果⽂档中插⼊值到⼀个数组中
$first: 根据排序获取第1个
$last: 根据排序获取最后1个
三、练习题
测试数据如下:
var persons = [{
name:"jim",
age:25,
email:"75431457@qq.com",
c:89,m:96,e:87,
country:"USA",
books:["JS","C++","EXTJS","MONGODB"]
},
{
name:"tom",
age:25,
email:"214557457@qq.com",
c:75,m:66,e:97,
country:"USA",
books:["PHP","JAVA","EXTJS","C++"]
},
{
name:"lili",
age:26,
email:"344521457@qq.com",
c:75,m:63,e:97,
country:"USA",
books:["JS","JAVA","C#","MONGODB"]
},
{
name:"zhangsan",
age:27,
email:"2145567457@qq.com",
c:89,m:86,e:67,
country:"China",
books:["JS","JAVA","EXTJS","MONGODB"]
},
{
name:"lisi",
age:26,
email:"274521457@qq.com",
c:53,m:96,e:83,
country:"China",
books:["JS","C#","PHP","MONGODB"]
},
{
name:"wangwu",
age:27,
email:"65621457@qq.com",
c:45,m:65,e:99,
country:"China",
books:["JS","JAVA","C++","MONGODB"]
},
{
name:"zhaoliu",
age:27,
email:"214521457@qq.com",
c:99,m:96,e:97,
country:"China",
books:["JS","JAVA","EXTJS","PHP"]
},
{
name:"piaoyingjun",
age:26,
email:"piaoyingjun@uspcat.com",
c:39,m:54,e:53,
country:"Korea",
books:["JS","C#","EXTJS","MONGODB"]
},
{
name:"lizhenxian",
age:27,
email:"lizhenxian@uspcat.com",
c:35,m:56,e:47,
country:"Korea",
books:["JS","JAVA","EXTJS","MONGODB"]
},
{
name:"lixiaoli",
age:21,
email:"lixiaoli@uspcat.com",
c:36,m:86,e:32,
country:"Korea",
books:["JS","JAVA","PHP","MONGODB"]
},
{
name:"zhangsuying",
age:22,
email:"zhangsuying@uspcat.com",
c:45,m:63,e:77,
country:"Korea",
books:["JS","JAVA","C#","MONGODB"]
}]
for(var i = 0;i<persons.length;i++){
db.persons.insert(persons[i])
}
var persons = db.persons.find({name:"jim"})
while(persons.hasNext()){
obj = persons.next();
print(obj.books.length)
}
在mongodb中的效果如下:
(为什么测试数据,不能复制到mongodb终端中,待解决)
1.查询年龄大于25小于27的name,age
db.persons.find({age:{$gt:25,$lt:27}},{name:1,age:1})
2.查询出不是美国的name $ne 不等于
db.persons.find({country:{$ne:'USA'}},{name:1})
3.查询国籍是中国或者美国的学生信息
db.persons.find({$or:[{country:'USA'},{country:'China'}]})
4.查询语文成绩大于85或者英语成绩大于90的学生信息
db.persons.find({$or:[{c:{$gt:85}},{e:{$gt:90}}]})
5.查询出名字中存在"li"的学生信息
db.persons.find({name:/li/},{name:1})
6.查询喜欢看MONGODB和PHP的学生
db.persons.find({books:{$all:['MONGODB','PHP']}},{books:1})
7.查询第二本书是JAVA的学生信息
db.persons.find({'books.1':'JAVA'},{books:1})
8.查询喜欢的书数量是4本的学生
db.persons.find({books:{$size:4}},{books:1})
9.查询出persons中的国家分别是什么
db.persons.distinct('country')