MongoDB基础
一、mac安装MongoDB
1.使用homebrew安装
- 安装homebrew
- 使用brew安装MongoDB
brew install mongodb
- 新建一个目录
mkdir data
- 命令行中指定数据库路径
mongod --dbpath="./data"
- 出现waiting for connections on port 27017就表示启动成功
2.下载安装包安装
- 去官网下载对应的版本
- 解压后放入
/usr/local
目录下 - 配置环境变量
export PATH=${PATH}:/usr/local/MongoDB/bin
source .bash_profile
使配置生效。输入mongod -version
,回车后如果看到下面的版本号则说明MongoDB已经成功安装到了Mac上- 新建data文件夹,再建db文件夹。
sudo mkdir -p /data/db
mongod启动命令参数
--port
:指定服务端口号:默认为27017--logpath
:指定日志文件(不是目录)--logappend
:使用追加的方式写日志--dbpath
:指定数据库路径--directoryperdb
:设置每个数据库被保存在一个单独的目录
启动客户端
mongo
二、MongoDB基本概念
- 数据库:MongoDB单个实例可以容纳多个数据库。
admin
(权限) 要是将用户添加到这个数据库,这个用户自动继承所有数据库的权限。
local
用于存储限于本地单台服务器的任意集合
config
分片设置时,用于保存分片的相关信息。
- 集合:数据库由集合组成,类似于关系型数据库中的表
- 文档:集合组成文档,文档是一组键值对。
注:1.文档中的键值对是有序的。2.区分类型和大小写。3.文档不能有重复的键。
三、MongoDB常见的数据类型
数据类型 | 描述 |
---|---|
String | 字符串。在MongoDB中,UTF-8才是合法的 |
Integer | 整型数值。可分为32位或64位 |
Boolean | 布尔值 |
Double | 双精度 |
Min/Max | 将一根值与二进制JSON元素的最低值和最高值对比 |
Array | 用于将数组或列表的多个值村委一个键 |
Timestamp | 时间戳 |
Object | 用于内嵌文档 |
Null | 用于创建空值 |
Symbol | 用于采用特殊符号类型的语言 |
Date | 日期时间 |
Object ID | 对戏ID |
Binary Data | 二进制数据 |
Code | 文档中存储JavaScript代码 |
Regular expression | 存储正则表达式 |
四、数据库操作
- 查看所有数据库:
show dbs
- 选择数据库:
use test
返回
switched to db test
注:当选择的数据库未创建,也可以切换过来,但是无法查到,需要在数据库中插入数据才算创建完毕。
- 查看当前数据库:
db
或db.getName()
- 删除数据库:
db.dropDatabase()
返回
{"dropped":"test","ok":1}
五、集合操作
- 查看集合帮助:
db.test.help()
- 查看数据库下的集合:
show collections
- 创建一个空集合:
db.createCollection(collection_Name)
db.createCollection(movies)
返回{"ok":1}
- 创建集合并插入一个文档:
db.collection_Name.insert(movies)
db.douban.insert({name:'阿丽塔'})
返回
WriteResult({ "nInserted" : 1 })
5.删除集合:db.Collection_name.drop()
5.创建一个有上限的集合:db.createCollection("name",{capped:true,size:10})
capped:默认值为false表示不设置上限,true表示设置上限
六、文档操作
1.插入文档
- insert
db.collection_name.insert(document)
注:每插入一个文档,默认会生成一个_id
属性,用来作为文档的唯一标识,可以直接指定,但是如果集合中已经有了_id
的话,会插入失败。
- save
db.collection_name.save(document)
注:不指定_id
字段就类似于insert()
方法,如果指定了则会更新该_id
的数据。(存在则更新,不存在则添加)
2.更新文档
说明
db.collection.update(
<query>,
<updateObj>,
{
upsert:<boolean>,
multi:<boolean>
}
)
- query(必选) 查询条件,指定要更新的文档所符合的条件
- update(必选) 更新后的对象或指定一些更新操作符
$set
直接指定更新后的值
$inc
在原基础上累加
- upsert(可选),如果不存在符合条件是否插入,默认
false
不插入 - multi(可选),MongoDB默认只更新找到的第一条,设置为true,就更新所有符合条件的。必须和
$操作符
一起才有效。
简单例子:
update aritcle set title = "mongodb" where read > 100
db.article.update({"read"{">":100}},{"$set":{"title":"mongodb"}})
操作符
$inc
:在原基础上累加
db.grade1.update({name:"tom"},{$inc:{age:10}})
//tom age 累加10
$push
:向数组中添加元素,不会覆盖已有的
db.grade1.update({name:"tom"},{$push:{"hobby":reading}})
$addToSet
:给数组添加或设置一个值
db.grade1.update({_id:3},{$addToSet:{friends:'huge'}})
$pop
:删除数组的第一个或者最后一个元素
传入1删除最后一个,-1删除第一个
db.grade1.update({_id:3},{$pop:{friends:1}})
$each
:在$addToSet中使用时,若有则忽略,若没有则添加。在$push中使用时,不管有没有都会添加。$ne
:不等于
db.grade1.update({hobby:{$ne:"reading"}},{$push:{hobby:"drinking"}})
$set
:设置字段的值
/*原来的数据*/:
{_id:3, info:{id: '11'}, friends:['liudehua', 'zhourunfa']}
/*设置字段第一层的值*/
db.grade1.update({_id:3},{$set:{"info11":{id:"11"}}})
/*设置嵌套字段的值*/
db.grade1.update({_id:3}, {$set:{"info.id":'22'}})
/*修改指定索引元素*/
db.grade1.update({_id:3}, {$set:{"friends.1":'zhangmanyu'}})
$unset
:删除指定的键
db.grade1.update({name:tom},{$unset:{"age":""}})
3.删除文档
db.collection.remove(
<query>,
{
justOne:<boolean>
}
)
- query:(可选)删除文档的条件
- justOne:(可选)设为true或1,则只删除匹配到的多个文档中的第一个。默认为false删除全部
db.grade1.remove({"name":"tom"},{justOne:treu})
db.grade1.remove({"name":"tom"})
//删除全部匹配的文档
4.查询文档
- find()
db.collection_name.find(query,projection);
query:过滤器,条件
projection:指定匹配返回哪些键
/projection/
{ field1:, field2: ... }
1 or true: 在返回的文档中包含这个字段
0 or false:在返回的文档中排除这个字段
注:_id字段默认一直返回,除非手动将_id字段设置为0或false
db.grade1.find() //查询grade1下的所有文档
select * from grade1
db.grade1.find({},{"name":1,"age":1})
- findOne()
只返回匹配到的第一条文档
3.方法pretty():将结果格式化
db.集合名称.find({条件文档}).pretty()
查询操作符
$in
:在数组范围内
db.grade1.find({age:{$in:[9,11]}})
select * from grade1 where age in(9,11)
$nin
:不在数组范围内$not
:取反,为元语句,可以用在任何条件之上
4.$gt
:大于
5.$gte
:大于等于
6.$lt
:小于
7.$lte
:小于等于
8.$ne
:不等于
数组查询
原始数据
{ "_id" : 1, "name" : "Tom1", "age" : 9, "friends" : [ "Lily", "Jobs", "Lucy", "Zhang San" ] } { "_id" : 2, "name" : "Tom2", "age" : 15, "friends" : [ "Zhange San", "Li Si" ] } { "_id" : 3, "name" : "Tom3", "age" : 11, "friends" : [ "Zhange San", "Lily" ] }
db.grade1.find({"friends" : [ "Lily", "Jobs", "Lucy", "Zhang San" ]}) //只能查到一条
db.grade1.find({"friends" : [ "Lily" ]}) //返回空
db.grade1.find({"friends" :{$all: ["Lily","Zhang San"]}}) //$all 多个元素同时存在才能匹配成功
db.grade1.find({"friends" :{$in: ["Zhang San"]}}) //$in 范围查询
db.grade1.find({"friends" :{$size:4}}) //限制数组长度,只有为4才匹配
db.collection.find( { field: value }, { array: {$slice: count } } ); //当$slice的参数是一个时,表示返回的数量;当是一个数组时,第一个参数表示偏移量,第二个表示返回的数量。
通过_id查询
注:通过_id进行查询,需要加上ObjectId
db.grade1.find({_id: '5c91ed1bcc5f270bc6111d2c'}).count()
//0
db.grate1.find(_id:ObjectId("5c91ed1bcc5f270bc6111d2c")).count()
//1
正则匹配
db.collection.find({key:/value/})
db.grade1.find({name:/^T/})
或
db.grade1.find({name:{$regex:"^zh"}})
and、or
and:
db.grade1.find({field1:value1,field2:value2})
or:
db.grade1.find($or:[{key1:value1},{key2,value2}])
and和or联用
db.grade1.find({age:9,$or:[{name:tom1},{age:11}]})
分页查询
1.limit:控制返回数量
db.collection_name.find().limit(number)
2.skip:略过指定数量的数据
db.collection_name.find().skip(number)
3.sort:排序,使用 1 和 -1 来指定排序的方式,1为升序排列,而-1用于降序排列。
4.distinct:去重
db.collection_name.distinct(‘去重字段’,{条件})
数据的备份与恢复
mongodump -h dbhost -d dbname -0 dbdirectory
-h:服务器地址,端口号
-d:需要备份的数据库名称
-o:备份的数据存放位置
mongorestore -h dbhost -d dbname --dir dbdirectory
-h:服务器地址,端口号
-d:需要恢复的数据库实例
--dir:备份数据所在位置
聚合aggregate
聚合是基于数据处理的聚合管道,每个文档通过一个由多个阶段组成的管道,可以对每个阶段的管道进行分组、过滤等操作。然后经过处理再输出相应的结果。
db.集合名称.aggregate({管道:{表达式}})
常用管道如下(有些前面已经介绍过):
$group
:将集合中的文档分组,可用于统计结果$match
:过滤数据,只输出符合条件的文档$project
:修改输入文档的结构,如重命名、增加、删除字段、创建计算结果$sort
:将输入文档排序后输出$limit
:限制聚合管道返回的文档数$skip
:跳过指定的文档数,返回余下文档$unwind
:将数组类型的字段进行拆分
常用表达式:(语法:表达式:$列名)
$sum
:计算总和,$sum:1
表示以一倍计数$avg
:计算平均值$min
:获取最小值$max
:获取最大值$push
:在结果文档中插入值到一个数组中$first
:更加排序获取第一个文档的数据$last
:根据怕徐获取最后一个文档的数据
例子:
# 按性别分组的人数
db.stu.aggregate(
{$group:{_id:"$gender",count:{$sum:1}}
)
# 按hometown进行分组,获取不同组的平均年龄
db.stu.aggregate(
{$group:{_id:"$hometown",mean_age:{$avg:"$age"}}}
)
# 将集合中所有文档分为一组 _id为null
db.stu.aggregate(
{$group:{_id:null,counter:{$sum:1}}}
)
注:分组依据放
_id
后面
取不同的字段需要使用$
取字典嵌套的字典中的值时用$_id.country
可以按多个建同时进行分组
使用$group
统计整个文档
db.stu.aggregate(
{$group:{_id:null,count:{$sum:1}}}
)
使用$project
db.stu.aggregate(
{$group:{_id:"$gender",count:{$sum:1}},
{$project:{gender:"$_id",count:1,_id:0}}
)
# 修改输入输出的值
使用$match
#年龄大于20的学生,男性、女性有多少人
db.stu.agregate(
{$match:{age:{$gt:20}}},
{$group:{_id:"$gender",count:{$sum}}},
{$project:{_id:0,gender:$_id,count:1}}
)
# 上一步的结果作为下一步的输入
db.stu.aggregate(
{$group:{_id:{country:$country,province:$province}}},
{$group:{_id:{country:"$_id.country",province:"$_id.province"}}},
{$project:{country:"$_id.country",province:"$_id.province",_id:0}}
)
$unwind
的使用
# 先插入数据
db.t1.insert([
{"_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}]
)
#使用$unwind将数组字段进行拆分
db.t1.aggregate({$unwind:"$size"}) //null 不显示
db.t1.aggregate( [
{ $unwind: { path: "$sizes", preserveNullAndEmptyArrays: true } }
] ) //保留属性值为空的文档
索引
建立索引:
db.集合.ensureIndex({属性:1}),1表示升序,-1表示降序
例子:
# 先在集合中插入数据作为测试
for(i=1;i<1000000;i++){db.t1.insert({name:"test"+i,age:i})}
# 查询性能分析
db.t1.find({name:"test100000"}).explain("executionStats")
# 建立索引
db.t1.ensureIndex({name:1})
# 默认_id为索引,上面语句会新建一个索引。再次查询会发现查询速度变快了
# 查看当前集合的所有索引
db.t1.getIndexes()
# 删除索引
db.t1.dropIndex("索引名称":1)
# 创建唯一索引
# 根据关键字段建立 唯一索引,可以对数据进行去重
db.t1.ensureIndex({name:1},{unique:true})
# 建立联合索引
db.t1.ensureIndex({name:1,age:1})
爬虫数据去重(增量式爬虫):
- 根据url地址进行去重(url地址唯一,对应的数据不会改变)
判断url地址是否在redis的集合中,存在就是请求过,不再请求
不存在,请求并将url存入redis集合中。
- 根据数据本身进行去重
选择特定的字段,使用加密算法(md5,sha1)将字段进行加密,生成字符串
新的数据进行相同的加密,如果相同,则看情况更新。不存在,直接插入。
布隆过滤器:
使用多个加密算法加密url地址,得到多个值。
将对应值的位置设置为1
新的url地址通过算法也生成多个值
如果对应位置全为1,说明被抓过,否则就将对应位置值设为1
参考:
https://www.runoob.com/mongodb/mongodb-remove.html
http://ghmagical.com/article/page/id/Bj7qgmJ3CJUE