mongoDB入门与集群搭建

来源:互联网 发布:think in java第四版 编辑:程序博客网 时间:2024/06/08 15:45

1.mongoDB对比与基础

对比项 mongoDB mysql oracle 表 文档document 一条记录record 表的一行数据 key 字段field 字段值 value value 主外键 无 主键 外键 灵活度扩展性 极高 差

首先配置完环境变量
然后设置一个数据库地址 并启动服务 mongod - -dbpath F:\MongodData
然后启动 mongo 127.0.0.1:27017

查看数据库列表 : show dbs
创建数据库 : use 库名
查看所在库下的集合列表 : show collections
给指定数据库添加集合 : db.[documentName].insert({})
db.[documentName].save({}) 在_id相同的情况下不报错
查询指定文档数据 : db.[documentName].find() 查询所有
db.[documentName].findOne() 查询第一条
更新文档数据 : db.[documentName].update({查询条件},{更新内容}) 只更新查找到的第一条
db.[documentName].update({查询条件},{更新内容},true) 当第一个查询结果没数据时,会执行插入
db.[documentName].update({查询条件},{更新内容},false,true) 第四个参数true,代表更新所有查找道的内容
删除文档数据 : db.[documentName].remove({删除条件}) 集合本身和索引不删除
删除库中集合 : db.[documentName].drop()
删除数据库 : db.dropDatabase()
帮助 : 数据库相关 db.help() 集合相关 db.[documentName].help()
api 文档 : http://api.mongodb.com/js

mongoDB 中的bson 比 json 支持类型多的部分

1 2 null 正则 boolean JavaScript代码块 32位和64位整数 undefined 64位浮点 数组 utf–8 内嵌文档 对象id _id:ObjectId() 二进制 日期

2.修改器

名称 语法 说明 $set {$set:{field:value}} 它用来指定一个键值对,存在则修改,不存在则添加 $inc {$inc:{field:value}} 对指定值进行加减操作 $unset {$unset:{field:value}} 删除指定键 $push {$push:{field:value}} 他会把你插入的值放进一个默认创建数组中,@如果插入键不存在,则创建;@如果插入键不是数组类型,报错 $pushAll {$push:{field:array}} 插入数组类型的元素,所以插入值的类型必须是数组 $addToSet {$addToSet:{field:value}} 如果目标数组存在此项则不操作,不存在则添加 $addToSet {$addToSet:{field:value}} 如果目标数组存在此项则不操作,不存在则添加 $pop {$pop:{field:value}} 从指定数组中删除一个值,如果值是正的,则删除第一个值;负的,则删除最后一个值 $pull {$pull:{field:value}} 从指定数组中删除一个指定值, $pullAll {$pullAll:{field:array}} 从指定数组中删除多个指定值,只接受数组类型

数组定位器$
这个我举个例子
比如

{ "_id" : 1, "child" : [ { "type" : "java" }, { "type" : "java" }, { "type" : "php" } ] }

我们想在数组内部的对象中再插入一个键值,让它变成

{ "_id" : 1, "child" : [ { "type" : "java" ,"age":25}, { "type" : "java" }, { "type" : "php" } ] }

就可以这么操作

db.集合名.update({"child.type":"java"},{"child.$.age":25})

3.查询

查询条数:db.[documentName].find().count()
去重: db.runCommand({distinct:"documentName",key:"field"})
等同于 db.documentName.distinct(field)
分组:

db.runCommand({group:{            ns:集合名字,            key:分组的键对象,            initial:初始化累加器,            $reduce:组分解器,            Condition:条件,            Finalize:组完成器}})

例子:请查出集合中每个国家学生人数中,数学成绩最好的学生信息(90分以上)

db.runCommand({group:{            ns:"Students",            key:{"country":true},            initial:{grade:0},            $reduce:function(doc,prev){                if(doc.m>prev.m){                    prev.grade=doc.grade;                    prev.name=doc.name;                    prev.country=doc.country;                    }            }            Condition:{grade:{$gt:90}},            Finalize:prev.grade=prev.name+"数学成绩是:"+prev.grade}})
条件操作符 含义 $lt 小于 $lte 小于等于 $gt 大于 $gte 大于等于 $ne 不等于

1.查询指定字段:

db.[documentName].find({查询条件},{指定字段})

例:db.[documentName].find({age:{},{_id:0,age:1})
字段指定0为不显示,1为显示,不指定默认不显示,_id除外
2.查询条件
2.1查询出年龄在25到27岁的人

db.person.find({age:{$gte:25,$lte:27}},{_id:0,age:1})

不是:$ne
3.包含或不包含(必须跟数组)

$in $nindb.[documentName].find({country:{$in:["CHINA","USA"]}})

4.OR查询

db.[documentName].find({$or:[{ 条件1},{条件2}]})

5.Null
这和js是一样的
6.正则查询
查询出名字中存在wu的人

db.persons.find({name:/wu/i})

7.$not
可以用到任何地方进行取反操作
$nin的区别在于前者可用于任何地方

db.persons.find({name:{$not:/wu/i}})

8.数组查询$all和index应用
注:books为数组
查询喜欢mongoDB和java的人

db.persons.find({books:{$all:["mongoDB","java"]}})

查询喜欢第二本书是java的人

db.persons.find({books.1:"java"})

9.查询指定长度数组 $size 不能与比较查询符一起使用

db.persons.find({books:{$size:4}})

10.$slice操作符返回文档中指定数组的内部值
查询出jim书架中第2-4本书

db.persons.find({name:"jim"},{books:{$slice:[1,3]}})

查询出最后一本书

db.persons.find({name:"jim"},{books:{$slice:-1}})

总结:查询器一般放在大括号里面,而更新器是放在外面

11.文档查询$elemMatch
查询出在K上过学的学生
这个以前的方式也能解决
完全匹配:

db.persons.find({school:{school:"K"},score:"A"})db.persons.find({school.school:"K",school.score:"A"})错误db.persons.find({school.school:"K",school.score:"B"})

正确做法:

db.persons.find({school:{$elemMatch:{school:"K",score:"A"}}})

12.$where
查询年龄大于22岁,喜欢看c++书,在K学校上过学的学生信息
复杂查询可以用$where 万能,但是性能不高

db.persons.find({"$where":function(){        //得到查询结果的每一条文档        var books=this.books;        //取得school对象        var school=this.school;        //如果年龄>22        if(this.age>22){            var php=null;            //遍历            for(var i=0;i<books.length;i++){                if(book[i]=="c++"){                   php=book[i];                   //如果学校存在                   if(school){                      for(var j=0;j<school.length;j++){                           if(school[j].school=="K"){                               return true;                           }                      }            }       break;     }})

1.limit返回数据条数
查询前5条数据

db.persons.find().limit(5)

2.skip返回5-10条

db.persons.find().skip(5).limit(5)

3.sort返回按照年龄排序的数据[1,-1]

db.persons.find({},{_id:0,name:1,age:1}).sort({age:1})

不同类型的优先级
最小值 > null > 数字 > 字符串 > 对象/文档> 数组 >二进制 > 对象ID> 布尔 > 日期> 时间戳 > 正则 > 最大值
4.skip性能问题,数据量大时
每次查询操作的时候前后台传值前要把上次的最后一个文档的日期保存下来

db.persons.find({date:{$gt:日期数值}}).limit(3)

1.游标
利用游标遍历查询数据

var persons=db.persons.find();while(persons.hasNext()){        obj=persons.next();        print(obj.name)}

2.游标几个销毁条件
1.客户端发来信息销毁
2.游标迭代完毕
3.默认游标超过10分钟自动销毁
3.查询快照
快照后就会针对不变的集合进行游标运动了

db.persons.find({$query:{name:"jim"},$snapshot:true})

高级查询选项

$query$orerby$maxsaninteger最多扫描的文档数$min:doc 查询开始$max:doc 查询结束$hin:doc 使用哪个索引$explain:boolean 统计$snapshot:boolean 一致快照

4.为什么有的时候要用查询快照?
当我们遍历一个大的文档对象时,假设这个文档对象里面存的都是一个个文档,但我们遍历到某个特别大的文档时,预留内存不够需要扩充内存,这时文档的顺序就会改变,大的文档就会被放到后面去,这就可能引起重复读取数据。
如果我们开启快照,那么文档的顺序就不会变了。
mongDB内存分配:
当document被创建的时候DB会为其分配内存和预留内存,当修改操作不超过预留内存的时候,则速度非常快,反而超过了就要分配新的内存则会消耗时间。

4.索引

1.创建简单索引

db.books.ensureIndex({number:1})

2.索引的注意
1.创建索引的时候 1是正序创建索引 -1是倒序创建索引
2.索引的创建在提高查询性能的同时会影响插入的性能,对于经常查询少插入的文档可以考虑索引
3.符合索引要注意索引的先后顺序
4.每个键全建立索引不一定能提高性能
5.在做排序工作的时候如果超大数据量也可以考虑
3.索引的名称

db.books.ensureIndex({name:-1},{name:"bookname"})

4.唯一索引
4.1不能插入重复的数值

db.books.ensureIndex({name:-1},{unique:true})

5.如果已有重复的,如何建立唯一索引

db.books.ensureIndex({name:1},{unique:true,dropDups:true})

6.hint
强制查询使用指定索引

db.books.find({name:"book",number:1}).hint({}name:-1)

7.expain
查看本次查询使用的哪个索引(调出查询信息)

db.books.find({name:"book"}).explain()

1.system.indexes
查询索引

show collectionssystem.indexes     db.system.indexes.find()     db.system.namespace.find()

2.后台执行
执行创建索引的过程会暂时锁表如何处理
为了不影响查询我们可以叫索引的创建过程在后台

db.books.ensureIndex({name:-1},{background:true})

3.删除索引

db.runCommand({dropIndexes:"books"},index:"name")db.runCommand({dropIndexes:"books"},index:"*")

4.2D索引
1.查询出距离点(70,180)最近的3个点

db.map.ensureIndex({"gis":"2d"},{min:-1,max:201})

默认会建立一个[-180,180]之间的2d索引
查询点(70,180)最近的3个点

db.map.find({"gis":{$near:[70,180]}},{gis:1,_id:0}).limit(3)

2.查询以点(50,50)换个点(190,190)为对角线的正方形中的所有的点

db.map.find({gis:{"$within":{$box:[[50,50],[190,190]]}}},{_id:0,gis:1})

3.查询出以圆心为(56,80)半径为50规则下的圆心面积中的点

db.map.find({gis:{$within:{$center:[[56,80],50]}}},{_id:0,gis:1})

5.固定集合

2.固定特性
2.1固定集合默认是没有索引的就算是_id也是没有索引的
2.2由于不需分配新的空间他的插入速度是非常快的
2.3固定集合的顺是确定的导致查询速度是非常快的
2.4最适合的应用就是日志管理
3.创建固定集合
3.1创建一个新的固定集合要求大小是100个字节,可以存储文档10个

db.createCollection("mycoll",{size:100,capped:true,max:10})

3.2把普通集合转换成固定集合

db.runCommand({convertToCapped:"persons",size:100000})

4.反向排序,默认是插入顺序排序.
4.1查询固定集合mycoll并且反向排序

db.mycoll.find().sort({$natural:-1})

5.尾部游标,可惜shell不支持java和php等驱动是支持的
5.1尾部游标概念-
这是个特殊的只能用到固定级和身上的游标,他在没有结果的时候也不回自动销毁他是一直等待结果的到来

6.GridFS

1.概念
GridFS是mongoDB自带的文件系统它用二进制的形式存储文件
大型文件系统的绝大多事特性GridFS全可以完成
2.利用的工具
mongodiles.exe
3.使用GridFS
3.1查看GridFS所有功能
cmd - -mongofiles
3.2上传一个文件

mongodfiles -d foobar -l "E:\a.txt" put "a.txt"

3.3查看GridFS的文件存储状态
集合查看

db.fs.chunks.find()和db.fs.files.find()

存储了文件系统的所有文件信息
3.4查看文件内容

mongofiles -d foobar get "a.txt"

3.5查看所有文件

mongofiles -d foobar list

3.6删除已存在的文件

mongofiles -d footer delete 'a.txt'

7.Javascript相关

1.Eval
1.1服务端运行eval

db.eval("function(name){return name}","uspcat")

2.Javascript的存储
2.1在服务上保存js变量活着函数供全局调用
1.把变量加载到特殊集合system.js中

db.system.js.insert({_id:name,value:"uspcat"})

2.调用
db.eval(“return name”)
System.js相当于orale中的存储过程,引文value不单单可以写变量还可以写函数体,也就是javascript代码

8.mongoDB启动与数据操作

1.mongo启动项

参数 说明 --dbpath 指定数据库的目录,不置顶会有一个默认目录 --port 指定服务器监听的端口号,默认是27017 --fork 用守护进程的方式启动mongoDB --logpath 指定日志的输出路径,默认是控制台 --config 指定启动项用文件的路径 --auth 用安全认证方式启动数据库

1.导出数据(中断其他操作)
利用mongoexport
-d 指明使用的库
-c 指明要导出的表
-d 指明要导出的文件名
-csv 制定导出的csv格式
-q 过滤导出
- -type json、csv、tsv
1.1 把数据从foobar中的persons导出

mongoexport -d foobar -c persons -o D:/persons.json

1.2导出其他主机数据库的文档

mongoexport --host  - -port

2.导入数据(中断其他操作)
API
http://cn.docs.mongodb.org/manual/reference/mongoimport/
2.1导入persons文件

mongoimport --db footer --collection persons --file d:/persons.json

1.运行时备份mongodump
API
http://cn.docs.mongodb.org/manual/reference/mongodump/
1.1导出127.0.0.1服务下的27017下的foobar数据库

mongodump --host 127.0.0.1:27017 -d footer -o d:/foobar

2.运行时恢复mongorestore
API
http://cn.docs.mongodb.org/manual/reference/mongorestore/
2.1删除原来的数据库用刚才导出的数据库恢复

db.dropDatabase()mongorestore --host 127.0.0.1:27017 -d footer -directoryperdb d:/foobar/foobar

3.懒人备份
mongoDB是文件数据库这其实就可以用拷贝文件的发那个方式进行备份

Fsync锁 数据修复
1.上锁和解锁
上锁

db.runCommand({sync:1,lock:1})

解锁

db.currentOp()

3.数据修复
当停电等不可逆转灾难来临时,犹豫mongodb等存储结构导致会产生垃圾数据,在数据恢复以后这垃圾数据依然存在,这是数据库提供一个自我修复的能力。

db.repairDatabase()

9.用户管理,安全认证

user文档,定义了用户的以下形式:

{ user: "<name>",  pwd: "<cleartext password>",  customData: { <any information> },  roles: [    { role: "<role>", db: "<database>" } | "<role>",    ...  ]}

user文档字段介绍:
user字段,为新用户的名字;
pwd字段,用户的密码;
cusomData字段,为任意内容,例如可以为用户全名介绍;
roles字段,指定用户的角色,可以用一个空数组给新用户设定空角色;
在roles字段,可以指定内置角色和用户定义的角色。

Built-In Roles(内置角色):1. 数据库用户角色:read、readWrite;2. 数据库管理角色:dbAdmin、dbOwner、userAdmin;3. 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager;4. 备份恢复角色:backup、restore;5. 所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase6. 超级用户角色:root  // 这里还有几个角色间接或直接提供了系统超级用户的访问(dbOwner 、userAdmin、userAdminAnyDatabase)7. 内部角色:__system

w选项:允许的值分别是 1、0、大于1的值、”majority”、;
j选项:确保mongod实例写数据到磁盘上的journal(日志),这可以确保mongd以外关闭不会丢失数据。设置true启用。
wtimeout:指定一个时间限制,以毫秒为单位。wtimeout只适用于w值大于1。

1.添加一个用户
1.1在products数据库创建用户wujiawei,并给该用户admin数据库上clusterAdmin和readAnyDatabase的角色,products数据库上readWrite角色。

use productsdb.createUser( { "user" : "wujiawei",                 "pwd": "123456",                 "customData" : { employeeId: 12345 },                 "roles" : [ { role: "clusterAdmin", db: "admin" },                             { role: "readAnyDatabase", db: "admin" },                             "readWrite"                             ] },               { w: "majority" , wtimeout: 5000 } )

2.启用用户
db.auth(“名称”,”密码”)
3.安全检查 --auth
非foobar是不能操作数据库的
非admin用户是不能使用数据库命令的
admin数据库中的数据经过认证为管理员用户
4.用户删除操作

db.system.users.remove({user:"wjw"})

11.mongoDB主从复制

这里写图片描述
1.1在数据库集群中要明确的知道谁是主服务器,主服务器只有一台
1.2从服务器要知道自己的数据源也就是对于主服务是谁
1.3–master用来确定主服务器,–slave和-source来控制从服务器

从服务器配置:dbpath=...    #从数据库地址port=...        #从数据库端口号bind_ip=127.0.0.1    #从数据库所在服务器source=...#这个配置项(source)可以用shell动态添加slave =true     #确定自己是从服务器主服务器配置:dbpath=...   #主数据库地址port =...   #主数据库端口号bind_ip=...   #主数据库所在服务器master=true    #确定我是主服务器

2.主从复制的其他设置项
–only 从节点 指定复制某个数据库,默认是复制全部数据库
–slavedelay 从节点 设置主数据库同步数据的延迟(单位 秒)
–fastsync 从节点 以主数据库的节点快照为节点启动从数据库
–autoresync 从节点 如果不同步则重新同步数据库
–oplogSize 从节点 设置oplog的大小(主节点操作记录存储到local的oplog中)

3.利用shell动态添加和删除从节点
从节点关于主节点的信息全部存到local的sources的集合中,我们只要对集合进行操作就可以动态操作主从关系
挂接主节点操作之前只留下从数据库服务

db.sources.insert({"host":"127.0.0.1:8888"})

删除已经连接的主节点,操作之前只留下从数据库服务

db.sources.remove({"host":"127.0.0.1:8888"})

12.副本集

这里写图片描述
主服务器是活跃的,从服务器为主服务器备份
当主服务器出现故障,集群会根据权重算法推选出其中一台从服务器为活跃服务器
当故障恢复后,自动为主服务器备份

服务器A
dbpath=…
port=…
bind_ip=127.0.0.1 #服务地址
replSet= repset #副本集名称

服务器B
dbpath=…
port=…
bind_ip=127.0.0.1 #服务地址
replSet= repset

服务器C
dbpath=…
port=…
bind_ip=127.0.0.1 #服务地址
replSet= repset

2.初始化副本集

use admin  config={    "_id":"repset",    members:[{        "_id":1,        "host":"127.0.0.1:2000"    },{         "_id":2,        "host":"127.0.0.1:4000"    }]  }  rs.initiate(config)

在不设置权重下,随机推选
2.查看副本集状态

rs.status()

3.节点和初始化高级参数
standard常规节点:参与投票有可能成为活跃节点
passive副本节点:参与投票,但是不能成为活跃节点
arbiter仲裁节点:只是参与投票不复制节点也不能成为活跃节点

4.高级参数
Priority 0到1000之间。0代表是副本节点,1到1000水常规节点
arbiterOnly:true 仲裁节点
用法

member:[{    "_id":1,    "host":"127.0.0.1:1111",    arbiterOnly:true}]

5.优先级相同的时候仲裁组建的规则
首先会比较 数据的完整性,1秒前更新的肯定比5秒前更新的优先级高,这个优先级占的权重是最高的

6.读写分离操作
6.1一般情况下作为副本的节点是不能进行数据库读操作的,但是在读取密集型的系统中读写分离是非常必要的
6.2设置读写分离
slaveOkay:true

7.oplog
他是被存储在本地数据库local中的,他的每一个文档保证这一个节点操作,如果项故障恢复可以更彻底oplog可以尽量设置大一些用来保存更多的操作信息
该表oplog的大小
主库 –master –oplogSize size

13.分片技术

这里写图片描述
1.什么时候用分片
1.1机器的磁盘空间不足
1.2单个的mongoDB服务器已经不能满足大量的插入操作
1.3想通过把大量数据放到内存中来提高性能

2.分片步骤
2.1创建一个配置服务器
2.2创建路由服务器,并且连接配置服务器
路由器是调用mongos命令
2.3添加2个分片数据库
8081和8082
2.4利用路由为集群添加分片(允许本地访问)

db.runCommand({addshard:"127.0.0.1:8081",allowLocal:true})db.runCommand({addshard:"127.0.0.1:8082",allowLocal:true})

配置服务器
dbpath=…
port=2000
bind_ip=127.0.0.1
configsvr=true #标识配置服务器
replSet= repset #副本集的名称
新版本分片默认配置服务器使用副本集
配置服务器的副本集为基数个数

路由服务器
mongos启动
port=3000
configdb=repset/127.0.0.1:2000,127.0.0.1:4000,127.0.0.1:5000
bind_ip=127.0.0.1
configdb:监听配置服务器

分片1
dbpath=…
port=8081
bind_ip=127.0.0.1
shardsvr=true

分片2
dbpath=…
port=8082
bind_ip=127.0.0.1
shardsvr=true

利用路由为集群添加分片
db.runCommand({addshard:”127.0.0.1:8081”,allowLocal:true})
db.runCommand({addshard:”127.0.0.1:8082”,allowLocal:true})

打开数据分片功能,为数据库hotel打开分片功能(路由服务器)
db.runCommand({“enablesharding”:”hotel”})

对集合进行分片(以_id为分片规则)
db.runCommand({“shardcollection”:”hotel.roomcat”,”key”:{“_id”:1}})
同 sh.enableSharding(“库名”)、sh.shardCollection(“库名.集合名”,{“key”:1})
删除片键可直接在路由服务器config集合下删除

查看配置库对于分片服务器的配置存储
sh.status()
具体可以查看
https://docs.mongodb.com/manual/reference/method/js-sharding/

为分片指定tag
首先开启集合分片

sh.addShardTag(片键名,tag名)

sh.addTagRange (
sh.addTagRange( “库名.集合”,
{ age: 1},
{ age: 20},
“tag名”
)
这个时候age在1~20范围内都会被存入指定片键内

分片与副本集一起使用
这里写图片描述

本次mongoDB 版本为 3.4

原创粉丝点击