目录:
(3)MongoDB作为非关系型数据库相较于关系型数据库的优点:
(3)定义实现随机User-Agent的下载中间件---豆瓣实例
前言:
爬虫(基础):python爬虫(基础)_qwerdftgu的博客-CSDN博客
一、MongoDB
官方文档:https://docs.mongodb.com/
1.mongodb介绍
(1)什么是mongodb
- mongodb是一个功能最丰富的NoSQL非关系数据库。由C++语言编写。
- mongodb本身提供S端存储数据,即server;也提供C端操作处理〈如查询等)数据,即client。
(2)SQL和NO-SQL的主要区别
- 据库>集合>文档
数据的无关联性:
- SQL中如果需要增加外部关联的话,规范化做法是在原表中增加一个外键,关联外部数据表。
- NoSQL则可以把外部数据直接放到原数据集中,以提高查询效率。缺点也比较明显,对关联数据做更新时会比较麻烦。
- SQL中在一个表中的每条数据的字段是固定的。而NoSQL中的一个集合(表)中的每条文档(数据)的key(字段)可以是互不相同的。
(3)MongoDB作为非关系型数据库相较于关系型数据库的优点:
- 易扩展:NoSQL数据库种类繁多,但是一个共同的特点都是去掉关系数据库的关系型特性。数据之间无关系,这样就非常容易扩展
- 大数据量,高性能:NoSQL数据库都具有非常高的读写性能,尤其在大数据量下表现优秀。这得益于它的非关系性,数据库的结构简单
- 灵活的数据模型:NoSQL无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。而在关系数据库中,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是一个梦
(3)mongodb安装
2.mongodb的使用
(1)简单使用
1. 服务端的启动:
- 默认端口号:27017
- 默认配置文件的位置:/etc/mongodb.conf
- 默认日志的位置:/var/log/mongodb/mongodb.log
两种方式启动:
本地测试方式的启动(只具有本地数据的增删改查的功能)
验证数据库能否正常运行
生成方式启动(具有完整的全部功能)
部署启动2. mongodb数据库的命令:
- 查看当前的数据库:db(没有切换数据库的情况下默认使用test数据库)。查看所有的数据库:how dbs /show databases
- 切换数据库:use db_name
db_name为show dbs后返回的数据库名- 删除当前的数据库:db.dropDatabase()
3. mongodb集合的命令:
- 无需手动创建集合:向不存在的集合中第一次添加数据时,集合会自动被创建出来
- 手动创建集合:
db.createCollection(name,options)
db.createCollection("stu"")
db.createCollection("sub", { capped : true,size : 10})
参数capped:默认值为false表示不设置上限,值为true表示设置上限
参数size︰集合所占用的字节数。当capped值为true时,需要指定此参数,表示上限大 小,当文档达到上限时,会将之前的数据覆盖,单位为字节- 查看集合:show collections
- 蒯除集合:db.集合名称.drop0
- 检查集合是否设定上限: db.集合名.isCapped0
- 测试代码:
show dbsuse test show collections db db.stu.insert(i " name ' :"郭靖','age ':22}) show dbs show collections db.stu.find() db.stu.drop() show collections db.dropDatabase() show dbs exit
4. mongodb中常见的数据类型:
- 常见类型:
Object ID: 文档ID/数据的ID,数据的主键(默认为索引)
String: 字符串,最常用,必须是有效的UTF-8
Boolean: 存储一个布尔值,true或false(小写)
Integer: 整数可以是32位或64位,这取决于服务器
Double: 浮点数
Arrays: 数组/列表
Object: mongodb中的一条数据/文档,即文档嵌套文档
Null: 存储null值
Timestamp: 时间戳,表示从1970-1-1到现在的总秒数
Date:存储当前日期或时间的UNIX时间格式- 注意点:
- 每个文档都有一个属性,为_id,保证每个文档的唯一性,mongodb默认使用_id作为主键
可以手动设置_id的值,如果没有提供,那么MongoDB为每个文档提供了一个 独特的_id,类型为objectlD- objectID是一个12字节的十六进制数,每个字节两位,一共是24位的字符串:
。前4个字节为当前时间戳
。接下来3个字节的机器ID
。接下来的2个字节中MongoDB的服务进程id。最后3个字节是简单的增量值
(2)mongodb的增删改查
1. mongodb插入数据:
- 命令:db.集合名称.insert(document)
db.stu.insert((name : ' gj ', gender:1))
db.stu.insert({_id:"201701e1",name :" gj' , gender:1})
- 插文档时,如果不指定_id参数,MongoDB会为文档自动分配一个唯一的Objectld
2.mongodb的保存
- 命令:db.集合名称.save(document)
db.stu.save({_id: '20170101', name : ' gj', gender:2})
db.stu.save({name : 'gi‘ , gender:2})
db.stu.find()
- 如果文档的_id已经存在则修改,如果_id不存在则添加(插入)
3.mongodb的查询
3.1 简单查询
- 方法find():查询
db.集合名称.find({条件文档})- 方法findOne():查询,只返回第一个
db.集合名称.find0ne({条件文档})- 方法pretty0:将结果格式化;不能和findOne()一起使用! 美化!!!!
db.集合名称.find({条件文档}).pretty()
3.2 比较运算符
- 等于:默认是等于判断,没有运算符。
- 小于: $lt (less than)
- 小于等于:$lte(less than equal)。
- 大于: $gt(greater than)
- 大于等于: $gte
- 不等于: $ne
查询年龄大于18的所有学生
db.stu.find({age:{$gte: 18}})
3.3 逻辑运算符:逻辑运算符主要指与、或逻辑.
- and:在json中写多个条件即可
查询年龄大于或等于18,并且性别为true的学生
db.stu.find({age :{$gte:18},gender:true})
- or:使用$or,值为数组,数组中每个元素为json
查询年龄大于18,或性别为false的学生
db.stu.find({$or:[iage:{$gt:18}}, {gender:false)]})
查询年龄大于18或性别为男生,并且姓名是郭靖
db.stu.find({$or:[{age:{$gte:18}},{gender:true}], name : 'gj'})
3.4 范围运算符
- 使用$in , $nin判断数据是否在某个数组内
查询年龄为18、28的学生
db.stu.find({age:{$in: [18,28]}})
3.5 使用正则表达式
- 使用$regex编写正则表达式
查询name以'黄'开头的数据
db.stu.find({name:{$regex:"^黄"}})
3.6 自定义查询:
mongodb shell 是一个js的执行环境 使用$where 写一个函数,返回满足条件的数据
查询年龄大于30的学生
db.stu.find( {
$where:function() {
return this.age>30;}
})
3.7 skip和limit(查询结果的操作)
- 方法limit():用于读取指定数量的文档
db.集合名称.find( ).limit(NUMBER)
查询2条学生信息
db.stu.find().limit(2)
- 方法skip0:用于跳过指定数量的文档
db.集合名称.find( ).skip(NUMBER)
db.stu.find().skip(2)
- 同时使用-------> 可以实现翻页操作
db.stu.find().limit(4).skip(0) # 四条数据
db.stu.find().skip(4).limit(4) # 接着四条数据
3.8 投影
在查询到的返回结果中,只选择必要的字段
命令: db.集合名称.find({}, {字段名称:1,---})
参数为字段与值,值为1表示显示,值为0不显 特别注意∶
- 对于_id列默认是显示的,如果不显示需要明确设置为0
- 对于其他不显示的字段不能设置为0
db. stu.find({}, {_id :0, name: 1, gender: 1})
3.9 排序
方法sort(),用于对查询结果按照指定的字段进行排序
- 命令: db.集合名称.find().sort({字段:1,...})
参数1为升序排列,参数-1为降序排列
根据性别降序,再根据年龄升序(复合排序)
db.stu.find().sort({gender : -1, age:1})
3.10 统计个数(和去重)
方法count)用于统计结果集中文档条数
- 命令: db.集合名称.find({条件}).count()
- 命令: db.集合名称.count({条件})
db.stu.find({gender:true}).count()
db. stu.count({age:{$gt:20}, gender:true})
- 命令: db.集合名称.distinct(字段,{查询条件})
db.stu.distinct("hometown") # 对整个数据去重
db.stu.distinct("hometown", {age:18}) # 对查询结果去重!!()
4. mongodb的更新
db.集合名称.update({query}, {update}, {multi: boolean})
- 参数query:查询条件
- 参数update:更新操作符
- 参数multi:可选,默认是false,表示只更新找到的第一条数据,值为true表示把满足条件的数据全部更新
db.stu.update({name : 'hr'}, {name: 'mnc'}) # 全文档进行覆盖更新
此时该条数据只有一个内容即:{name: "mnc"}, 还有id
db.stu.update({name : 'hr' }, {$set:{name: 'hys'}) # 指定键值更新操作
db.stu.update({}, {$set:{gender:0}}, {multi: true}) # 该数据库中的数据全部更新
db.stu.update({name: "qdd"}, {$set: {age: 18}, {upsert: true}} # 找到则该,没有就插入
注意: "multi update only works with $ operators"
- multi参数必须和$set一起使用!!
5. mongodb的删除
db.集合名称.remove({query}, {justOne: boolean})
-参数query:可选,删除的文档的条件
-参数justone:可选,如果设为true或1,则只删除一条,默认false,表示删除全部小结
- mongo shell中的增:
db.集合名.insert({数据})
db.集合名.save({包含_id的完整数据})#根据指定的_id进行保存,存在则更新,不存在 则插入- mongo shell中的删:
db.集合名.remove({条件}, {justOne: true/false})- mongo shell中的改:
db.集合名.update({条件}, {$set:{完整数据/部分字段}}, {multi: true/false})- mongo shell中的查:
db.集合名.find({条件}, {字段投影})
(3)mongodb的聚合操作
1. mongodb的聚合是什么
聚合(aggregate)是基于数据处理的聚合管道,每个文档通过一个由多个阶段(stage)组 成的管道,可以对每个阶段的管道进行分组、过滤等功能,然后经过一系列的处理, 输出相应的结果。
语法: db.集合名称.aggregate({管道:{表达式}})
2. mongodb的常用管道和表达式
2.1 常用的管道命令
在mongodb中,文档处理完毕后,通过管道进行下一次处理常用管道命令如下
- $group: 将集合中的文档分组,可用于统计结果(!!!!!!!最重要)
- $match: 过滤数据,只输出符合条件的文档
- $project: 修改输入文档的结构,如重命名、增加、删除字段、创建计算结果
- $sort: 将输入文档排序后输出
- $linit: 限制聚合管道返回的文档数
- $skip: 跳过指定数量的文档,并返回余下的文档
2.2 常用表达式
表达式:处理输文档并输出语法:表达式:"$列名·常用表达式:
- $sun : 计算总和, $sum:1表示以一倍计数(可以用于数据计数)
- $avg : 计算平均值
- $min : 获取最小值
- $max︰获取最大值
- $push : 在结果文档中插入值到一个数组中
3 管道命令之 $group !!!!!!!!!!!!!!!!!!!!非常重要
3.1 按照某个字段进行分组
$group是所有聚合命令中用的最多的一个命令,用来将集合中的文档分组,可用于统计结果使用示例如下
db.stu.aggregate( {$group: { # $gender表示取含有gender字段的数据 _id:"$gender", # 这个_id表示的不是分组之前的键,而是分组结果中的键 counter:{$sum: 1} } } )
其中注意点;
- db.db_name. aggregate 是语法,所有的管道命令都需要写在其中
- _id表示分组的依据,按照哪个字段进行分组,需要使用$gender表示选择这个字段进行分组
- $sum:1 表示把每条数据作为1进行统计,统计的是该分组下面数据的条数
3.2 group by null
当我们需要统计整个文档的时候,$group的另一种用途就是把整个文档分为一组进行统 计使用实例如下:db. stu.aEgregate( {$group: { _id:null, counter:{$sum: l} # counter不是固定的,是你自己可以随便取得 } } )
其中注意点; 一条数据又称为文档
- _id: null 表示不指定分组的字段,即统计整个文档,此时获取的 counter表示整个文档的个数
3.3 数据透视
正常情况在统计的不同性别的数据的时候,需要知道所有的name,需要逐条观察,如 果通过某种方式把所有的name放到一起,那么此时就可以理解为数据透视
使用示例如下;
- .统计不同性别的学生
db.stu.aggregate( {$group: { id:null, name:{$push:"$name"} # push 放 } } )
- 使用$$ROOT可以将整个文档放入数组中
db.stu.aggregate( {$group: { _id:null, name:{$push: "$$ROOT"} } } )
4. 其它管道命令
4.1 $match
$match用于进行数据的过滤,是在能够在聚合操作中使用的命令,和 find 区别在于 smatch操作可以把结果交给下一个管道处理,而find不行
使用示例如下:
- 查询年龄大于20的学生
db.stu.aggregate( {$match:{age:{$gt:20}} )
- 查询年龄大于20的男女学生的人数
db.stu.aggregate( {$match:{age:{$gt:20}), {$group:{_id:"$gender", counter:{$sum:1}}} )
4.2 $projiect ----->类似投影
$project用于修改文档的输入输出结构,例如重命名,增加,删除字段
使用示例如下:
- 查询学生的年龄、姓名,仅输出年龄姓名
db.stu.aggregate( {$project: {_id: 0, name:1, age:1}} )
- 查询男女生人生,输出人数
db.stu.aggregate( {$project: {_id:"$gender", counter:{$sum:1}}}, {$project: {_id:0, counter:1} )
4.3 $limit和$skip
- $limit限制返回数据的条数
- $skip跳过指定的文档数,并返回剩下的文档数
- 同时使用时先使用skip在使用limit
使用示例如下:
- 查询2条学生信息
db.stu.aggregate( {$limit:2} )
- 查询从第三条开始的学生信息
db.stu.aggregate( {$skip:3} )
- 统计男女生人数,按照人数升序,返回第二条数据
db.stu.aggregate( {$group:{_id: "$gender", counter:{$sum:1}}}, {$sort:{counter: -1}}, {$skip:1}, {$limit:1} )
(4)mongodb-索引
1. 创建mongodb索引的作用:
- 加快查询数据
- 进行数据去重
2. 创建简单的索引方法
- 语法:db.集合名.ensureIndex({属性: 1}},1表示升序, -1表示降序
3. 创建索引前后查询速度对比:
插入数据:
for(i=0; i<100000; i++){ db.stu.insert( {name: 'text' + i, num:i} ) }
创建索引前:
db.stu.find({name:'text10000'}).explian('exectionStats') # 显示查询操作的详细信息
创建索引:
db.stu.ensureIndex({name:1})
创建索引后:
db.stu.find({name:'test10000'}).explain('exectionStats')
前后速度对比:
4. 索引的查看
默认情况下_id是集合的索引查看方式: db.集合名.getIndexes()
5. 删除索引
- db.集合名.dropIndex({索引名称:1})
- db.集合名.dropIndex()
6. 创建唯一索引
在默认情况下mongdb的索引域的值是可以相同的,创建唯一索引之后,数据库会在插入数据的时候检查创建索引域的值是否存在,如果存在则不会插入该条数据,但是创建索引仅仅能够提高查询速度,同时降低数据库的插入速度。
6.1 添加唯一索引的语法:
- db.集合名.ensureIndex({'字段名': 1}, {'unique':