目录
1. 安装
2. 基本命令
2.1 数据库和集合命令
数据库基本命令 | |
---|---|
db | 查看当前所在的数据库 |
show dbs/ show databases | 查看所有数据库 |
use 数据库名 | 切换数据库 |
db.dropDatabase() | 删除当前所在的数据库 |
集合collection相当于关系型数据库的表,也是不必须手动创建,当第一次插入数据的时候就会创建了
显示创建集合命令 | |
---|---|
db.createCollection(name,options) | |
db.createCollection("memeda") | 创建名字为 memeda 的集合 |
db.createCollection("memeda", { capped: true, size: 10} ) | 创建memeda集合,并且限制大小,最大为10字节,超过之后就会 新来的数据覆盖最早的数据 |
基本集合命令 | |
---|---|
show collections | 显示当前数据库中所有的集合 |
db.集合名.drop() | 删除集合 |
2.2 mongodb数据类型
- Object ID: ⽂档ID
- String: 字符串, 最常⽤, 必须是有效的UTF-8
- Boolean: 存储⼀个布尔值, true或false
- Integer: 整数可以是32位或64位, 这取决于服务器
- Double: 存储浮点值
- Arrays: 数组或列表, 多个值存储到⼀个键
- Object: ⽤于嵌⼊式的⽂档, 即⼀个值为⼀个⽂档
- Null: 存储
null
值 - Timestamp: 时间戳, 表示从1970-1-1到现在的总秒数
- Date: 存储当前⽇期或时间的UNIX时间格式
Date类型的使用
对应python的 datetime类型
new Date('2017-12-20') // 17年12月
new Date(2018,0,1) // 18年1月1日
ObjectId
- 每个⽂档都有⼀个属性, 为
_id
, 保证每个⽂档的唯⼀性 - 可以⾃⼰去设置_id插⼊⽂档,如果没有提供, 那么MongoDB为每个⽂档提供了⼀个独特的_id, 类型为
objectID
ObjectID
是⼀个12字节的⼗六进制数:- 前4个字节为当前时间戳
- 接下来3个字节的机器ID
- 接下来的2个字节中MongoDB的服务进程id
- 最后3个字节是简单的增量值
2.3 基本数据命令
CRUD数据基本命令 | |
---|---|
db.集合名.insert( document ) | 插入数据(document是一个json |
db.集合名.save(document) | 保存, 如果_id 在collection中已经存在则修改,否则插入新数据 |
db.集合名.find() | 返回集合内的所有数据 |
db.集合名.update( 查询条件,更新后结果, {multi: false}) | 根据查询条件匹配,更新数据,默认更新一条 |
db.集合名.remove(查询条件, {justOne: false}) | 根据查询条件删除数据,默认删除多条匹配 |
a. 插入
db.集合名.insert( document )
示例:
db.stu.insert({name:'gj',gender:1})
db.stu.insert({_id:"20170101",name:'gj',gender:1})
如果插入的document不包含 _id
,则mongo会自动设置一个文档id字段_id
,类型为ObjectId
b. 保存
db.集合名.save(document)
插入+修改。 如果document中有_id
,并且collections中也有对应的数据,那么就会修改原数据;否则插入新数据
示例:
db.mongodemo.save({_id:"123456789", name:"zhouwang", age:17 })
c. 简单查询
db.集合名.find()
d. ★更新
db.集合名称.update(<query> ,<update>,{multi: <boolean>})
- 参数query:查询条件
- 参数update:更新操作符
- 参数multi:可选, 默认是false,表示只更新找到的第⼀条记录, 值为true表示把满⾜条件的⽂档全部更新
示例:
# 将第一条匹配的 name为zhouwang的,更新为 age为20
# 注意--> 这会完全替换,除了 _id保留,其他属性只剩下了 age:20
db.mongodemo.update({name:"zhouwang"}, {age:20})
# 使用$set 能够指定部分更新,而不是全部替换
db.mongodemo.update({name:"zhouwang"},{$set:{ age:30, gender:"male"} })
# 同时更新多条
db.mongodemo.update({name:"zhouwang"}, {$set: {age:20}}, {multi:true})
e. ★删除
db.集合名称.remove(<query>,{justOne: <boolean>})
- 参数query:可选,删除的⽂档的条件
- 参数justOne:可选, 如果设为true或1, 则只删除⼀条, 默认false, 表示删除多条
3. 高级查询
方法 |
---|
db.集合名.find( 条件 ) |
db.集合名.findOne( 条件 ) |
db.集合名.find( 条件).pretty() |
比较运算符
运算符 | 示例 | |
---|---|---|
$lt | 小于 | db.mongodemo.find({age: {$lt: 26} }) |
$lte | 小于等于 | |
$gt | 大于 | |
$gte | 大于等于 | |
$nt | 不等于 |
判断年龄年龄范围的写法是:
db.mongodb.find({ age : {$gt: 20} }, age : {$lt: 40})
范围运算符
运算符 | 示例 | |
---|---|---|
$in | 在范围内 | |
$nin | 不在范围内 | db.mongodemo.find({ name: { $nin : [ "haha", "a", "b"] } }) |
逻辑运算符
- 与 —— 直接写多个条件
db.mongodemo.find( {name : "hsy", age :{$lt: 30}} )
- or ——
$or
db.mongodemo.find( { $or: [{name : "hsy"}, { age :{$lt: 30}} ] } )
正则
- 在
/
和/
里面写正则:db.集合名.find( {name : /^abc/} )
- 使用
$regex
:db.集合名.find( { name : {$regex: "^abc" }} )
分页操作
运算符 | 示例 | |
---|---|---|
db.集合名.find().limit(n) | 拿几个 | |
db.集合名.find().skip(n) | 跳过几个 | db.mongodemo.find().skip(3).limit(2) |
建议先skip再limit
自定义条件
$where
- 自己定义函数,返回true
- 可以使用
this
访问到每条数据
db.集合名.find({
$where: function(){
if this.age < 18;
return true;
}
})
投影
db.集合名.find(条件, 投影字段)
控制哪条返回,哪条不返回
- 1代表显示,0代表不现实
- _id字段默认显示
- 不要混合使用 1 和 0,否则会报错
db.stu.find({条件}, { _id: 0, _sex: 0, name: 0})
排序
db.集合名.find().sort({排序字段})
- 1代表正序, -1代表逆序
db.stu.find.sort( age: -1, gender: 1})
统计个数
db.集合名.count(条件)
db.集合名.find({条件}).count()
去重
db.集合名.distinct(字段名, 条件)
db.集合名.distinct("name", {age: 40} )
4. 聚合
聚合是基于数据处理的聚合管道, 每个文档(数据)通过一个 由** “多阶段”组成的管道**, 可以多每个阶段的管道进行分组、过滤、匹配等操作,最后输出结果
语法:
db.集合名.aggregate(
{管道: { 表达式 } },
{管道: { 表达式 } },
...
)
常用管道 | 说明 |
---|---|
$group | 分组,可用于统计结果—— group by null 可以返回所有 |
$match | 按照条件匹配数据,用于过滤 |
$project | 投影, 修改文档结果 |
$sort | 排序 |
$skip | 跳过指定数量的文档,并且返回其他的 |
$limit | 限制返回的文档数目 |
$ unwind | 将数组类型的字段进行拆分 |
常用表达式 | 说明 |
---|---|
$sum | 计算和 —— $sum:1 可以用于统计数目 |
$avg | |
$min | |
$max | |
$push | 在结果文档中插入一个值到数组中 |
$first | 获取第一个文档结果 |
$last | 获取最后一个文档结果 |
4.1 $group
$group
对应的字典中有几个键,结果中就有几个键- 使用
_id
指定按照哪个分组 - 聚合使用的列名前都要加上
$
- 能够同时按照多个键进行分组
{$group:{_id:{country:"$country",province:"$province"}}}
- 结果是:
{_id:{country:"",province:""}
- 结果是:
案例
- 将结果按照 age 分组:
db.mongodemo.aggregate({$group: {_id: "$age" } })
>
{"_id":30}
{"_id":26}
{"_id":52}
- 将结果按照age分组,并且显示组每组有多少人
db.mongodemo.aggregate({$group: {_id: "$age", count: {$sum:1} } })
{"_id":30, "count": 1 }
{"_id":26, "count": 2}
{"_id":52, "count": 1}
- 按照性别分类,然后 输出获取平均值
db.mongodemo.aggregate( {$group: { _id: "$gender", avg_age: {$avg : "$age"} } } )
- 把所有数据作为一组,计算
db.mongodemo.aggregate( {$group: { _id: null, count: {$sum:1}, avg_age: {$avg : "$age"} } } )
- 按照age分组,然后将每个数据的name值显示成列表
db.mongodemo.aggregate({$group: {_id:"$age", names:{ $push: "$name" } } })
4.2 $project
- 每一个管道处理都是
aggregate
的一个参数 - 上一个管道的结果将作为下一个管道的输入
案例
- 按照gender进行分组,获取不同组数据的个数和平均年龄
db.stu.aggregate(
{$group:{_id:"$gender",count:{$sum:1},avg_age:{$avg:"$age"}}},
{$project:{gender:"$_id",count:1,avg_age:"$avg_age",_id:0}}
)
4.3 $match
- 用来过滤,聚合内不能使用
find
案例
- 选择年龄大于20的学生,观察男性和女性有多少人
db.stu.aggregate(
{$match:{$or:[{age:{$gt:20}},{hometown:{$in:["蒙古","⼤理"]}}]}},
{$group:{_id:"$gender",count:{$sum:1}}},
{$project:{_id:0,gender:"$_id",count:1}}
)
4.4 $sort
4.5 skip 和 limit
4.6 $unwind
- 将文档的某一个数组类型的字段拆分出来 变成多条文档
案例
- 数据库有一个:
{"username":"Alex", "tags": ["C#", "Java", "C++"] }
, 获取该tag数组的长度:
db.mongodbdemo.aggregate(
{$match: { username: "Alex" } } ,
{$unwindw : "tags"}
{$group: {_id:null, count : {$sum:1 }} }
)
- 防止没有该字段、字段为空数组、字段为""的数据丢失
5. 数据备份和还原
- 备份:
- 还原
6. 索引
目的: 提高查询速度
- 查询命令花费的时间:
db.xxx.find().explain('executionStats)
- 默认
_id
字段是有索引的
命令 | 说明 |
---|---|
db.集合名.ensureIndex({属性: 1或者-1}) | 建立索引 |
db.集合名.ensureIndex({属性: 1或者-1}, {"unique": true}) | 建立唯一索引 |
db.集合名.ensureIndex({属性: 1或者-1}, {"unique": true, "dropDups": true}) | 建立唯一索引并且丢弃重复 |
db.集合名.ensureIndex({属性1:1, 属性2:1 }) | 建立联合索引 |
db.集合名.getIndexes() | 查看当前集合的所有索引 |
db.集合名.dropIndex("索引字段名") | 删除索引 |
- 1代表升序, -1代表降序(除非需要升序或者降序操作,否则1或者-1区别不大)
7. 数据去重思路
爬虫数据去重,实现增量式爬虫
方法: 使用数据库建立关键字段(一个或者多个)建立索引进行去重
-
根据url地址进行去重
使用场景:url地址对应的数据不会变的情况,url地址能够唯一判别一个条数据的情况1. 使用redis的集合 2. 布隆过滤器 - 使用多个加密算法加密url地址,得到多个值 - 往对应值的位置把结果设置为1 - 新来一个url地址,一样通过加密算法生成多个值 - 如果对应位置的值全为1,说明这个url地址已经抓过 - 否则没有抓过,就把对应位置的值设置为1
-
根据数据本省进行去重—— 加密后放入redis的集合中
选择特定的字段,使用加密算法(md5,sha1)讲字段进行假面,生成字符串,存入redis的集合中. 后续新来一条数据,同样的方法进行加密,如果得到的字符串在redis中存在,说明数据存在,对数据进行更新,否则说明数据不存在,直接插入
8. Python操作mongodb
from pymongo import MongoClient
client = MongoClient(host="192.168.1.162", port=27017) # 会自动去连接
collection = client.数据库名.集合名
# 插入
objId = collection,insert({"name":"哈哈", "age":100}) # 插入,会自动创建 _id
print(objId) # 插入操作会返回 _id
objIds = collection.insert_many([{},{},{}]) # 插入多条,效率更高
# 删除
collection.delete_one({"name":"哈哈"})
collection.delete_many({"name":"哈哈"})
# 查找
cursor = collection.find() # 返回一个cursor
for data in cursor:
print(data)
collection.find_one({"name":"哈哈"}) # 返回一条数据
# 更新
collection.update_one({"name":"哈哈"}, {"$set": {"name":"yy"} } )
collection.update_many({"name":"哈哈"}, {"$set": {"name":"yy"} } )