![7cff0bd696359728f5daed3af7a2b153.png](https://img-blog.csdnimg.cn/img_convert/7cff0bd696359728f5daed3af7a2b153.png)
1、mongodb基本命令
1、查看当前数据库:db
2:查看所有数据库:show dbs / show databases
3、切换数据库: use +数据库名字
4、删除当前的数据库:db.dropDatabase()
2、集合(collection)的基本命令
1、展示特定数据库中所有集合:show collections
2、删除集合:db . 集合名 . drop()
3、向不存在的集合(collection)中第一次加入数据时,集合会被创建出来
4、手动创建集合db.createCollection(name,options)
如: db.createCollection(‘sub’,{capped:true,size:10})
参数capped:默认值为false,表示无上限,值为ture时表示设置上限
参数size:当capped值为true时,需要制定此参数,表示上限大小,当文档达到上限时候,讲会覆盖之前的数据,单位为字节。
3、数据类型
1、ObjectID:文档ID
2、String:字符串
3、Boolean:布尔值
4、Integer:整数
5、Double:存储浮点值
6、Arrays:数组或者列表,多个值存储到一个键
7、Object:用于嵌入式的文档,即一个值一个文档
8、Null:存储Null值
9、Timestamp:时间戳,表示从1970-1-1到现在的总秒数
10、Date:存储当前日期或者时间的UNIX时间格式
注意:
· 每个文档都有一个属性为:_id,保证每个文档的唯一性,
· 可以自己去设置_id插入文档,如果没有提供,那么MongoDB为每个文档提供一个独特的_id,类型为objectID
· objectID是一个12字节的十六进制数:
前4个字节为当前的时间戳
接下来3个字节为机器ID
接下来2个字节为MongoDB的服务进程id
最后3个字节是简单的增量值
4、基本操作
1、插入数据 save和insert的区别
db.collection.insert({}) 插入的数据,如果_id已经存在,则报错
db.collection.save({}) 插入的数据,如果_id已经存在,则会更新
2、简单查询 db.collection名.find()
3、更新 db.集合名称.update(<query>,<update>,{multi:<boolean>})
参数:query:查询条件
参数update: 更新操作符,更新成什么
参数multi:可选,默认是false,表示只更新找到的第一条记录,值为true表示把满足条件的文档全部更新
例子:
db.collection.update({name:’xiaoming’},{name:’xiaohua’ })
结果是:数据中除了_id,只剩下了name字段,其他的字段没有了
db.collection.update({name:’xiaoming’},{$set:{name:’xiaohua’} })
结果是:数据中只更新了name字段,其他的字段正常显示
db.collection.update({},{$set:{name:’xiaohua’} },{multi:true}) 更新全部
4、删除 db.集合名称.remove(<query>,{justOne:<boolean>})
参数query:可选,删除的文档的条件
参数justOne:可选,如果设为true或者1,则只删除一条,默认为false,表示删除多条(默认删除满足所有条件的记录)
5、高级查询
1、find() :查询所有
2、findOne() : 查询,只返回第一个 db.集合名称.findOne({})
3、pretty() :将结果格式化 db.集合名称.findOne({}).pretty()
6、运算符
1、比较运算符
· 等于:默认就是等于,没有运算符
· 小于:$lt
· 小于等于: $lte
· 大于: $gt
· 大于等于 : $gte
· 不等于 : $ne
例子: db.集合名称.find({ age:{ $gte: 18 } })
2、范围运算符
$in ,$nin 判断是否在某个范围内
如:查询年龄为18,28,38的学生
db.集合名称.find( { age: { $in[18,28,38] } } )
3、逻辑运算符
and : 同时满足条件
db.集合名称.find( { age:18,name:’xiaoming ’} )
or:使用$or
例子:查询年龄大于18,或者姓名为false的学生
db.集合名称.find( { $or:[{age:{$gt:18}} , { gender:false }] } )
4、mongodb支持正则表达式
例子:查找sku属性以adb开头
db.products.find({sku:/^abc/})
例子:查找sku属性以789结尾
db.products.find({sku:{/$regex:’789$’/}})
7、高级操作
1、limit 和 skip
limit() : 用于读取指定数量的文档
db.stu.find().limit(2)
skip() : 用于跳过指定数量的文档
db.stu.find.skip(2)
同时使用
db.stu.find.skip(5).limit(4)
2、自定义查询 $where
使用$where后面写一个函数,返回满足条件的数据
查询年龄大于30的学生
db.stu.find( {
$where : function () {
return this.age>30; //this 指定是每一条
}
} )
3、投影
在查询到的返回结果中,只选择必要的字段
db.集合名称.find({ } , { 字段名称:1,... })
参数为字段与值,值为1表示显示,值为0则不显
特殊:对于_id 列默认是显示的,如果不显示需要明确设置为0
db.stu.find({ } , { _id:0,name:1 } )
4、排序
sort() :用于对集进行排序
db.集合名称.find().sort( { 字段1:1,... } )
参数1:升序排列, -1为降序排列
5、统计个数
count() : 统计结果集的文档条数
两种书写方式
①:db.collection.find( {条件} ).count()
②:db.collection.count({条件})
6、消除重复
distinct() : 对数据进行去重
db.集合名称.distinct(‘去重字段’,{条件})
例子:db.stu.distinct(‘hometown’, { age: {$gt: 18}})
注意:当sort,skip,limit一起使用时,无论其位置变化,总是先sort再skip,最后limit
8、数据的备份和恢复
备份的语法(cmd命令)
mongodump -h dbhost -d dbname -o dbdirectory
-h : 服务器地址,也可以指定端口号
-d : 需要备份的数据库名称
-o : 备份的数据存放位置,此目录中存放着备份出来的数据
例子: mongodump -h 192.168.196.128:27017 -d test1 -o ~/Desktop/test1bak
数据恢复
恢复语法:
mongorestore -h dbhost -d dbname -dir dbdirectory
-h : 服务器地址,也可以指定端口号
-d : 需要恢复的数据库实例
-dir : 备份数据所在位置
9、聚合命令(难点)
聚合(aggregate)是基于数据处理的聚合管道,每个文档通过一个由多个阶段(stage)组成的管道,可以对每个阶段的管道进行分组,过滤等功能,然后经过一系列的处理,输出相应的结果。
db.集合名称.aggregate( { 管道: { 表达式 } } )
常用管道:
$group:讲集合中的文档分组,可用于统计结果
$match : 过滤数据,只输出符合条件的文档,类似于find()
$project : 修改输入文档的结构,如重命名、增加、删除字段、创建计算结果
$sort : 讲输入文档排序后输出
$limit : 限制聚合管道返回的文档数
$skip : 跳过指定数量的文档,并返回余下的文档
$unwind : 将数组类型的字段进行拆分
mongodb表达式
语法: 表达式 : ‘$列名’
$sum : 计算综总和,$sum:1 表示以一倍计数
$avg : 计算平均值
$min:计算最小值
$max :计算最大值
$push : 在结果文档中插入值到一个数组中
$first : 根据资源文档的排序获取第一个文档数据
$last: 根据资源文档的排序获取最后一个文档数据
$group
· 将集合中的文档分组,可用于统计结果
· _id 表示分组的依据(也就是依照哪个字段进行分组),使用某个字段的格式为 ‘$ 字段’
例1:统计男生、女生的总人数,按照gender分组,并计算每组平均年龄
db.stu.aggregate(
{ $group :
{
_id: ‘$gender’,
count:{ $ sum :1}, //计算总数,1:表示每一行计数1,这样总数就是每一组的总条数
avg_age:{ $avg: ‘$age’} //计算平均值
}
}
)
![v2-662a2fef97d8d57043edd549c9b8c0a8_b.png](http://img-03.proxy.5ce.com/view/image?&type=2&guid=0391d641-642b-eb11-8da9-e4434bdf6706&url=https://pic1.zhimg.com/v2-662a2fef97d8d57043edd549c9b8c0a8_b.png)
· group by null 将集合中所有的文档分为一组
例2:求学生总人数和平均年龄
db.stu.aggregate(
{$group :{
_id:null,
count:{$sum :1},
avg_age:{ $avg: ‘$age’}
}}
)
$project
输出的结果中如果不想显示_id的话,就要用到 $project
在这里加一个管道,$group输出的结果
db.stu.aggregate(
{$group :{ _id:’$gender’,count:{$sum :1},avg_age:{ $avg: ‘$age’}}},
{$project:{ gender:’$_id’,count:’$count’,avg_age:’$ave_age’}}
)
如果不想显示_id , 就写入_id:0, 正常显示的字段就写入 count:1
![8b7358618ae7aefb24cd5ddbb2938cbd.png](https://img-blog.csdnimg.cn/img_convert/8b7358618ae7aefb24cd5ddbb2938cbd.png)
$match
· 用于过滤数据,只输出符合条件的文档
· 使用MongoDB的标准查询操作
· 与find的区别:match是管道命令,能将结果交给后一个管道,但是find不可以
例1:查询年龄大于20的学生
db.stu.aggregate(
{$match : {age:{$gt : 20} }}
)
例2:选择年龄大于20的学生,观察男性和女性有多少人
db.stu.aggregate(
{$match : {age:{$gt:20}}},
{$group:{ _id:’$gender’,count:{$sum : 1} }},
{$project:{ gender:’$_id’, count:1 , _id:0}}
)
例3:小练习
{“country”: “china”,”province”:”sh”,”userid”:”a”}
{“country”: “china”,”province”:”sh”,”userid”:”b”}
{“country”: “china”,”province”:”sh”,”userid”:”a”}
{“country”: “uk”,”province”:”sh”,”userid”:”c”}
{“country”: “china”,”province”:”bj”,”userid”:”da”}
{“country”: “china”,”province”:”bj”,”userid”:”fa”}
要求:统计出每个country/province下的userid的数量(同一个userid只统计一次)
db.stu.aggregate(
//去重,通过将country、province和userid三个属性同时进行分类,那么一样的就会分到一组,然后输出,就达到了去重的作用
{$group:{ _id:{ country:”$country”,province:”$province”,userid:”$userid” } }},
{$group:{ _id:{ country:”$country”,province:”$province”}, count:{ $sum:1} }},
{$project:{_id:0,country:”$_id.country”,province:”$_id.province”, count:1 }}
)
$sort
· 将输入文档排序后输出
例1:查询学生信息,按照年龄升序
db.stu.aggregate(
{ $sort: { age:1 }}
)
例2:查询男生、女生人数、按照人数降序
db.stu.aggregate(
{$group:{ _id:”$gender”,count:{$sum:1} }}
{$sort:{ count:-1 }}
)
$limit和$skip
· $limit : 限制聚合管道返回的文档数
例1:查询2条学生信息
db.stu.aggregate({ $limit:2 })
· $skip : 跳过指定数量的文档,并返回余下的文档
例子2:查询从第3条开始的学生信息
db.stu.aggregate({ $skip:2 })
例3:统计男生、女生人数、按照人数升序、取第二条数据
db.stu.aggregate(
{ $group:{ _id:”$gender”,count:{ $sum:1 } } },
{ $sort:{count:1 } },
{ $skip:1 },
{$limit:1},
)
注意:先写skip,在写limit
$unwind
· 将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值
语法:db.集合名称.aggregate( {$unwind: “$字段名称” } )
例1:
db.stu.insert({ _id:1,item:’t-shirt’, size:[ ‘S’,’M’,’L’ ] })
db.stu.aggregate( {$unwind:’$size’} )
输出结果
{ _id:1,item:’t-shirt’, size:‘S’ }
{ _id:1,item:’t-shirt’, size:‘M’ }
{ _id:1,item:’t-shirt’, size:‘L’ }
练习:数据库找那个有一条数据:{“username”:”Alex”,”tags”:[“C++”,”Js”,”Java”]},如何获取tags列表的长度?
思路:
①:聚合查询,通过$match查找到这条数据
②:$unwind将tags拆分
③:$group获取数据的总条数
db.stu.aggragate(
{$match:{ username:”Alex” }},
{$unwind:”$tags”},
{$group:{ _id:null, count:{$sum:1} } }
)
$unwind的注意事项
如果数据库中有以下数据
{“_id”:1,“item”:”a”,”size”:[“S”,”M”,”L”]}
{“_id”:2,“item”:”b”,”size”:[ ]}
{“_id”:3,“item”:”c”,”size”:”M”}
{“_id”:4,“item”:”d”}
{“_id”:5,“item”:”e”,”size”:null}
运行:db.stu.aggregate({ $unwind:’$size’ })
结果
{“_id”:1“item”:”a”,”size”:”S”}
{“_id”:1,“item”:”a”,”size”:”M”}
{“_id”:1,“item”:”a”,”size”:”L”}
{“_id”:3,“item”:”c”,”size”:”M”}
而其他三条数据并没有返回,被删除了,那我们如何让它们正常返回呢?
就需要另一个参数:preserveNullAndEmptyArrays,当为true时,表示保留属性为空的文档
用法:
db.stu.aggregate(
{$unwind:{
path:’$字段名称’,
preserveNullAndEmptyArrays:<boolean> //防止数据丢失
}}
)
10、创建索引
1、索引:提升查询速度
语法:db.集合.ensureIndex( { 属性:1 } ), 1表示升序,-1表示降序
具体操作:db.t255.ensureIndex({name:1})
1或者-1,基本没什么差别,只有当需要排序的时候才有区别,比如,当降序的时候-1比较快,反之,1比较快
mongodb通过explain(“executionStats”)来检测查询的速度,输出结果中的属性executionTimeMillis值是查询所需要的的时间,单位为毫秒
测试:插入10万条数据到数据库中
for(i=0;i<100000;i++){db.t255.insert({name:’test’+i,age:i})}
建立索引之前
db.t255.find().explain(“executionStats”)
![e25b948773d2367acd28a51c7692fff4.png](https://img-blog.csdnimg.cn/img_convert/e25b948773d2367acd28a51c7692fff4.png)
建立索引后
db.t255.ensureIndex({name:1})
![2c6561bf0a132825533491f6d6afa708.png](https://img-blog.csdnimg.cn/img_convert/2c6561bf0a132825533491f6d6afa708.png)
第一个是mongodb默认以_id为索引,第二个是我们建立的索引
db.t255.find().explain(“executionStats”)
查询速度是0毫秒,这说明建立索引前后差距是很大的
![f49dc5374c6fe6ac0b47f25d33dc37f5.png](https://img-blog.csdnimg.cn/img_convert/f49dc5374c6fe6ac0b47f25d33dc37f5.png)
· 在默认情况下索引字段的值可以相同
· 创建唯一索引(索引的值是唯一的),这样可以去重,也是建立爬虫去重的思路之一
db.t1.ensureIndex({name:1},{“unique”:true})
简单讲一下爬虫数据去重,实现增量式爬虫
· 使用数据库建立关键字段(一个或者多个)建立索引进行去重
思路一: 根据url地址进行去重
① url地址对应的数据不会变的情况,url地址能够唯一判别一条数据的情况
② 首先,将url存到redis中,拿到url之后,判断url在redis的url集合中是否存在,
如果存在,说明该url已经请求过了,不再请求,如果不存在,说明该url没被请求过,
把url存入redis的集合中
③ 这方面有一个很厉害的算法:布隆过滤器
思路二:根据数据本身进行去重
①选择特定的字段,使用加密算法(md5,sha1)将字段进行加密,生成字符串,
存入redis的集合中
②后续新来一条数据,同样的方法进行加密,如果得到的字符串在redis中存在,
说明数据存在,对数据进行更新,否则说明数据不存在,直接插入
· 通过多个字段来判断数据的唯一性的时候可以建立联合索引
db.t1.ensureIndex({name:1},{age:1})
· 查看当前集合所有索引
db.t1.getIndexes()
· 删除索引
db.t1.dropIndex({‘索引名称’: 1})