mongodb
一、Mongodb学习笔记
基础实验方面>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
1.mongo:文档数据库,存储的是文档(Bson->json的二进制化)
特点:内部执行引擎为JS解释器,把文档存储为bson结构,在查询时转为js对象,并且可以通过js语法来操作
2.mongo与sql数据库相比:
sql数据库:结构化数据,定好了表格后,每一行的内容都是结构化的
mongo:文档数据,表下的数据都可以有自己的特点(有自己独特的属性和值),存储更加灵活
3.下载安装(直接去官网下载)
1.bin目录下文件解释:核心:
mongo:客户端
mongod:服务端
mongos:路由器(集群分片的时候用)
二进制导入导出:
mongodump:导出bson数据
mongorestore:导入bson数据
bsondump:bson转为json
mongolog:运行日志
数据导出导入:
mongoexport:导出容易识别json、csv、tsv格式文档
mongoimport:导入json、csv、tsv
运维工具:
mongosniff、mongotop、mongostat:观察mongo运行状态(运维时使用)
2.启动mongo服务:mongod --dbpath --logpath --fork(后台运行模式) --port 27017
4.mongo常用命令:
1.基本入门命令:
show dbs 查看当前数据库
use databaseName 选择数据库
show tables\collections 查看表
use databaseName 隐式创建数据库(如果存在则使用,不存在则在创建collection后创建此数据库,
如果没有创建collection,就不会创建库)
db.createCollection("collectionName") 直接创建表,不需要去定义结构(也可以隐式创建,在写入内容的时候自动创建)
db.collectionName.insert({key:value}) 往表中插入数据(创建数据的时候,如果没有指定_id的值,数据库会默认指定)
db.collectionName.find() 查看表中的数据
db.collectionName.drop() 删除collection(删除成功返回true,否则false)
db.collectionName.count() 统计数据条数
2.基本CURD命令:
增:
db.collectionName.insert({key:value}) 增加单个文档(key/value类型任意)
db.collectionName.insert({_id:intValue,key:value}) 增加并指定id,不指定会自动生成
db.collectionName.insert( 增加多个文档
[
{_id:1,key:value},
{_id:2,key:value}
]
)
删:
db.collectionName.remove({查询表达式,true\false}) 条件可以是特有的id、查询语句内容例如:{_id:10},就可以把这个文档_id:10删除
如果不写条件内容,整个collection都被清空,true则找到多个匹配也只删除一行, false则找到多少删除多少
查:find()、findOne()
db.collectionNmae.find({查询表达式,}) 查询表达式也为json格式,如果不写则全部查询
db.collectionName.find({查询语句},{key:1}) 查询某个属性,默认id也被查出来
db.collectionName.find({},{key:1,_id:0}) 查询某个属性,不查询_id,要查询的为1,不查询的不写,不查_id的必须写0
改:update({查询语句},新值,选项)
db.collectionName.update({表达式},{新值},可选参数) 新值会覆盖掉原来全部的内容----1
db.collectionName.update({表达式},{$set:{要修改的key->value}},{upsert:true}) 后面参数为可选,为true,则$set的内容存在则修改,不存在则添加,这样的话只修改需要修改的内容,其他不改变(修改某个列)--2
修改时的赋值表达式:$set 修改某个值(有则)
$unset 删除某个列key
$rename 重名某个列key
$incr 增长某个列
3.查询表达式深入:
1.最简单查询表达式
{field:value} 查询field列的值为value的文档
2.$ne (!=查询表达式)
{field:{$ne:value}} 查field列的值,不等于value的文档
3.$nin {}
4.$gt {大于}
{field:{$gt:value}}
5.$lt {小于}
{field:{$lt:value}}
6.$gte {大于或等于}
7.lte {小于或等于}
8.$in {在哪个区域内}
{field:{$in:[start:end]}
9.$all {所有}
{field:{$all:{[k1,k2,k3]}}} 同时存在k1,k2,k3采薇真
10.$or {$or:同下} 或
11.$and {$and:[{field:{条件}},{field:{条件}}]} 连接两个查询条件,将要连接的条件放在数组内
12.$nor {$nor:同上} 非
13.$not
14.$exists 某列存在则为true 取出存在某个列的文档
{field:{$exists:1}}
15.$mod:满足某求余条件为真
{field:{$mod:[5:0]}} 取出模5后等于0的列
16.$typc:数据为某类型则为真
这两种方式尽量少用,查询效率不高,大数据的时候
17.$where 表达式为真则为真
{$where:'this.key<100'} 说明:找出key对应value小于100的值(将二进制首先转为json,再比较,比较慢,表达式容易写)
18.$regex 正则表达式为真则为真
{$regex:{field:/正则表达式内容/}}
5.游标操作
1.解决一次性取出过多的数据
var mycursor=db.collectionName.find(query.project); 声明游标
mycurson.hasNext() 判断游标是否到末尾
cursor.Next(); 取出游标下一个单元
例子:
var mycursor=db.bar.find({_id:{$lte:5}})
print(mycursor.next()) //无法直接输出bson的值
printjson(mycursor.next()) //需要转为json格式输出
2.游标在分页中如何使用?使用skip()函数和limit()函数来查询
var mycursor=db.bar.find().skip(995); 说明前面跳过995行
mycursor.forEach(function(obj){printjson(obj)}); 系统的迭代函数(循环取出文档对象内容)
var mycursor=db.bar.find().skip(200).limit(10); 说明:跳过200条,取出10条;
mycursor.toArray(); 说明:也可以直接转为array,然后输出
mycursor.toArray()[1]; 说明:指明取出数组的第几个
6.索引
索引作用类型:
单列索引
多列索引
子文档索引
索引性质:
普通索引
唯一索引 db.bar.ensureIndex({field:1/-1},{unique:true}) 默认的_id就是唯一索引,索引的value不能重复
稀疏索引 db.bar.ensureIndex({field:1/-1},{sparse:true}) 稀疏索引:不存在的field不会建立索引,普通的话会建立对应
null
哈希索引 db.bar.ensureIndex({field:"hashed"}) 适用于随机性的散列,查询速度快,但是无法对范围查询进行优化
1.创建索引:db.bar.ensureIndex({field:1/-1}) 说明:参数为1是升序,-1是降序
db.bar.dropIndex({一个完整索引})
db.bar.dropIndexe() 说明:删除所有所引
2.多列索引:重要解释:健多列索引是把这几个列作为一个集合来查询,如果要查询多个列的时候
创建多列索引:db.bar.ensureIndex({表达式1,表达式2,.....})
3.子文档索引:
建立子文档索引:db.fruits.ensureIndex({'fieldName.fieldNameChild':1})
4.重建索引:一个表经过多次修改,导致表的文件产生空洞,索引文件也是,可以通过索引重建来提交的
db.collectionName.reIndex()
运维方面>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
7.用户管理
1.注意:
A、mongodb有个admin数据库,要进行服务器配置的操作,需要先切换到admin数据库,相当于切换到超级管理员
B、mongo的用户是以数据库为单位来建立的,每个用户有自己的管理员
C、在设置用户时,需要在admin数据库下建立管理员,这个管理员登录后相当于超级管理员
2.添加用户:
db.createUser({user:userName,pwd:userPassword,roles:[{role:"userAdminAnyDatabase",db:"admin"}]})
1.创建超级管理员
use admin
db.createUser(
{
user: "adminUserName",
pwd: "userPassword",
roles:
[
{
roles: "userAdminAnyDatabase",
db: "admin"
}
]
}
)
说明:超级用户的role有两种,userAdmin或者userAdminAnyDatabase(比前一种多加了对所有数据库的访问)。
db是指定数据库的名字,admin是管理数据库。
2. 用新创建的用户登录
mongo --host xxx -u adminUserName -p userPassword --authenticationDatabase admin
3. 查看当前用户的权限
db.runCommand(
{
usersInfo:"userName",
showPrivileges:true
}
)
4. 创建一般用户,也是用createUser
use db01
db.createUser(
{
user:"oneUser",
pwd:"12345",
roles:[
{role:"read",db:"db01"},
{role:"read",db:"db02"},
{role:"read",db:"db03"}
]
}
)
5. 创建一个不受访问限制的超级用户
use admin
db.createUser(
{
user:"superuser",
pwd:"pwd",
roles:["root"]
}
)
6. 修改密码
use admin
db.changeUserPassword("username", "xxx")
7. 查看用户信息
db.runCommand({usersInfo:"userName"})
8. 修改密码和用户信息
db.runCommand(
{
updateUser:"username",
pwd:"xxx",
customData:{title:"xxx"}
}
)
8.mongodb的导入与导出
1.导入导出可以操作本地数据库,也可以是远程的一般选项如下
-h 主机
-port port 端口
-u username 用户名
-p password 密码
2.mongodb导出的是json格式的文件 mongoexport (与其他数据库进行数据交互)
可以选择导出哪个库,哪个collection,哪几列,哪几行
-d 库名
-c 表名
-f field1,field2 列名
-o 导出的文件名
-q 查询条件
--cvs 导出cvs格式
导出csv格式:mongoexport.exe -d shop -c bar -f _id,aricle -q "{_id:{$let:100}}" --csv D:/data/export/myexport.csv
导出json格式:mongoexport.exe -d shop -c bar -f _id,aricle -q "{_id:{$let:100}}" D:/data/export/myexport.json
3.mongodb导入选项 mongoimport.exe
-d 待导入的数据库
-c 待导入的表
--type csv/json(默认为json)
--file 备份文件路径
json导入例子:mongoimport.exe -d shop -c im1(可以是存在的,不存在则自动创建) --type json --file D:/data/export/myexport.json
csv导入例子:mongoimport.exe -d shop -c im2 --type csv -f _id,article --file headerline(跳过第一行-->_id和article) D:/data/export/myexport.csv
4.二进制文件导出mongodump.exe 导出二进制bson结构及其索引信息(做备份,预防被攻击,数据丢失)
-d 库名
-c 表名
-f field1,field2 列名
例子:mongodump.exe -d shop -c im -o D:/data/export/
5.二进制文件导入mongorestore.exe 导入二进制文件
-d 库名
--directoryperdb 要导入的路径
例子:mongorestore.exe -d shop --directoryperdb D:/data/export/
9.replication复制集
replication set多台服务器维护相同的数据副本,提高服务器的可用性
1.启动3个服务,打开数据库方式:完整打开方式+“--replSet 复制集名” 把数据库都指向相同的复制集
Mongod.exe --dbpath D:/MongodbTest/data/db_17 --logpath D:/MongodbTest/data/log17/log17.log --logappend --port 27017
2.配置
var reconf={_id:'rs2',members:[{_id:0,host:'127.0.0.1:27017'},{_id:1,host:'127.0.0.1:27018'},{_id:2,host:'127.0.0.1:27019'}]}
3.根据配置做初始化
rs.initiate(reconf);
4.查看状态 rs.status
5.添加节点 rs.add("127.0.0.1:27020") 里面是要添加的端口号
6.删除节点 rs.remove("127.0.0.1:27020") 里面是要删除的端口号
10.shard分片
1.原因:数据量太大的时候(几亿眺),需要将不同的数据往指定的mongo存储
2.配置信息
1.要有(N>2)个mongo服务器做片节点
2.要有configserver维护meta信息
3.要设计好数据的分片规则(configsvr才方便维护)
4.要启动mongos做路由
3.动手操作
1.启动两台mongod作为分片服务---启动方式:与一般的启动方式相同----------------(27017+27018)
2.启动一台mongod作为configsever---启动方式正常启动方式+(--configsvr)()-------(27019)
以下操作均在mongos命令下完成
3.启动路由器:mongos.exe --logpath --port --configdb(指定路由服务的ip)------与configsvr联系
例如:mongos.exe --logpath D:/data/mslog.log--port 27030 --configdb 127.0.0.1:21019
4.mongos命令下增加节点(与片联系27017,27018)
命令:sh.addShard('IP:port')
例如:sh.addShard("127.0.0.1:21017")
5.查看状态:mongos命令下,sh.status()
6.configsvr设置
也是在mongo命令下
声明哪个库可以分片:sh.enableSharding('databasesName') 数据库名
例子:sh.enableSharding('shop') 商品数据库
声明哪个表分片 :sh.shardCollection('databasesName.collectionName',field) feild分片的键
例子:sh.shardCollection('databasesName.collectionName',{good_id:1}) 以商品id为键
chunk的概念:N个文档形成一个chunk
优先存在某个片上
当这片上的chunk比另一个片的chunk区别比较明显时(大于3),会把本片上的chunk移动到另一个上,以chunk为单位,维护片之间的均衡
详细内容:
问题1.为什么插入10万条数据,才有两个chunk?
答:configsvr数据库中chunk默认为64M,比较大,这里可以用命令修改
db.settings.find()---->找到chunk设置,默认chunk为64M
db.settings.save({_id:'chunksize',{set:{value:4}}}) 这里改为4
问题2.当随着数据的增多,shard之间有chunk来回移动,会带来哪些问题?
答:服务器之间的IO变大,速度会减慢
问题3.能否定义一个规则,某N条数据作为一个chunk,预先分配M个chunk,M个预分配在不同的片上,后面的数据直接进入 自己预分配好的chunk,不再来回移动
答:手动预先分片
实际操作:
1.预先分chunk:
sh.shardCollection('databasesName.collectionName',field)
for(var i=0;i<=40;i++){
sh.splitAt('databaseName.collectionName',{fieldkey:i*1000}) 说明:在1k-2k--切块
}
2.添加数据-->数据会添加到预先分配好的chunk上,chunk就不会再来回移动
11.replication和shard的结合使用
思路:将复制集主作为分片来使用,其他如分片操作一般
12.PHP-mongodb的扩展编译及应用案例
1.扩展编译步骤(win)
1.下载对应php-mongodb数据库的扩展
2.找到php_mongo.dll,复制到ext扩展文件夹下
3.php配置文件中添加;extction=php_mongo.dll
4.将php根目录下的libsasl.dll复制到apache的bin下即可配置成功
2.应用小案例(短网址应用生成案例)
这里省略
13.聚集运算之group
1.分组统计:groud()------------->不支持shard,无法分布式运算,需要我们自己写业务逻辑
等价的sql语法:select max(shop_price) from goods grounp by cat_id
语法:db.colllectionName.groud(document)--->{
key:{key1:1,key2:1}, 说明:相当于 "grounp by cat_id"
cond:{}, 说明:相当于 "where" 条件语句
reduce:function(curr,result){ 说明:自己写的一个聚合函数,实现业务逻辑
},
initial:{}, 说明 :进入时触发
finalize:function(){ 说明 :结束时触发
}
}
2.简单聚合:aggregate()--------->支持分布式运算
MongoDB 聚合
MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。有点类似sql语句中的 count(*)。
aggregate() 方法
MongoDB中聚合的方法使用aggregate()。
语法
aggregate() 方法的基本语法格式如下所示:
>db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
实例
集合中的数据如下:
{
_id: ObjectId(7df78ad8902c)
title: 'MongoDB Overview',
description: 'MongoDB is no sql database',
by_user: 'w3cschool.cc',
url: 'http://www.w3cschool.cc',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
},
{
_id: ObjectId(7df78ad8902d)
title: 'NoSQL Overview',
description: 'No sql database is very fast',
by_user: 'w3cschool.cc',
url: 'http://www.w3cschool.cc',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 10
},
{
_id: ObjectId(7df78ad8902e)
title: 'Neo4j Overview',
description: 'Neo4j is no sql database',
by_user: 'Neo4j',
url: 'http://www.neo4j.com',
tags: ['neo4j', 'database', 'NoSQL'],
likes: 750
},
现在我们通过以上集合计算每个作者所写的文章数,使用aggregate()计算结果如下:
> db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}])
{
"result" : [
{
"_id" : "w3cschool.cc",
"num_tutorial" : 2
},
{
"_id" : "Neo4j",
"num_tutorial" : 1
}
],
"ok" : 1
}
>
以上实例类似sql语句: select by_user, count(*) from mycol group by by_user
在上面的例子中,我们通过字段by_user字段对数据进行分组,并计算by_user字段相同值的总和。
下表展示了一些聚合的表达式:
表达式 描述 实例
$sum 计算总和。 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}])
$avg 计算平均值 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}])
$min 获取集合中所有文档对应值得最小值。 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}])
$max 获取集合中所有文档对应值得最大值。 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}])
$push 在结果文档中插入值到一个数组中。 db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}])
$addToSet 在结果文档中插入值到一个数组中,但不创建副本。 db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}])
$first 根据资源文档的排序获取第一个文档数据。 db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}])
$last 根据资源文档的排序获取最后一个文档数据 db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}])
3.强大统计:mapReduce()---->随着大数据的概念而流行
1.强大的地方:1.支持分布式
2.支持大量服务器同时工作,用蛮力来统计
2.工作过程:1.map-->映射 概念:把属于同一个组的数据映射到一个数组上,
2.reduce-->规约 概念:把数组的数据进行运算
3.map函数
var map=function(){
emit(this.cat_id,this.shop_price);
}
var reduce=function(key,value){
return Array.sum(values)
}
{
query query:{status:"A"};
output out:"order_totals"
}
var m=function(){emit(this.age,this.name);}
var r=function(age,name){return name}
{query:{},out:res}
db.emp.mapReduce(m,r,{out:'res'});
1.mapReduce重点解释:
MongoDB中的MapReduce相当于关系数据库中的group by。使用MapReduce要实现两个函数Map和Reduce函数。Map函数调用emit(key,value),遍历
Collection中所有的记录,将key与value传递给Reduce函数进行处理。
2、MapReduce
(1)其基本语法如下所示:
db.runCommand({
mapreduce:<collection>,
map:<mapfunction>,
reduce:<reducefunction>,
[,query:<query filter object>]
[,sort:<sorts the input objects using this key.Useful for optimization,like sorting by the emit key for fewer reduces>]
[,limit:<number of objects to return from collection>]
[,out:<see output options below>]
[,keeptemp:<true|false>]
[,finalize:<finalizefunction>]
[,scope:<object where fields go into javascript global scope>]
[,verbose:true]
});
参数说明:
Mapreduce:要操作的目标集合
Map:映射函数(生成键值对序列,作为reduce函数参数)
Reduce:统计函数
Query:目标记录过滤
Sort:目标记录排序
Limit:限制目标记录数量
Out:统计结果存放集合(不指定使用临时集合,在客户端断开后自动删除)
Keeptemp:是否保留临时集合
Finalize:最终处理函数(对reduce返回结果进行最终整理后存入结果集合)
Scope:向map、reduce、finalize导入外部变量
Verbose:显示详细的时间统计信息。
(2)执行查询的步骤
A.MapReduce对指定的集合Collection进行查询
B.对A的结果集进行mapper方法采集
C.对B的结果执行finalize方法处理
D.最终结果集输出到临时Collection中
E.断开连接,临时Collection删除或保留。
3、Map函数
Map函数调用当前对象进行处理,把值传递给reduce函数。Map方法使用this来操作当前对象,至少调用一次emit(key,value)方法向reduce提供参数。其中的key为最终结果集中的_id。
4、Reduce函数
该函数接受map函数传来的key和value值。reduce函数中的key就是emit(key,value)中的key,而value是emit函数中同一个key返回的value数组。
5.执行案例
map函数:
var map=function(){
if(this.age<20){
emit(this.age,{name:this.name});
}
}
var reduce=function(key,values){
var ciunt=0;
values.forEach(function(){count +=1;});
return count;
}
var result=db.runCommand(
{
mapreduce:"emp",
map:map
reduce:reduce,
out:"emp_result"
}
);
14.mapReduce实际应用案例(对地震数据的分析)
步骤:1.建立集群(复制集)
2.建立分片(shard)
3.将csv文件导入
4.mapReduce操作