博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

mongo 学习教程(全)

Posted on 2015-07-30 11:15  和风细雨汪汪  阅读(596)  评论(0编辑  收藏  举报

看的是爱酷学习网的视频:http://www.icoolxue.com/album/show/98

01

安装

1、先建mongoDB-data文件夹存数据

2、安装DB

3、设置环境变量:把bin目录:D:\mongodb\bin,添加到path下(;D:\mongodb\bin),好处是可以直接在cmd的命令行中输入mongod运行(这样也可检测),如果不设置环境变量,需要cd到当前目录下才能mongodb

启动

使用批处理文件来启动mongoDB,mongod.exe -dbpath d:\data

mongod help:查看常用的命令,mongodb启动命令参数说明:http://blog.csdn.net/fdipzone/article/details/7442162

27017:shell 客户端,28017:web

表:集合,行:文档

BSON对JSON的扩展,把json转为二进制码,增加了日期,浮点等json不支持的数据类型

nosql:集合(表),文档(行)。没有主键,关系数据库的每行的字段都是一样的,mongodb就不一定;关系数据库使用sql语句查询,mongodb使用find函数。

创建数据库:use foobar,只有加入相应的list,才会真正创建;

启动错误:32-bit servers don't have journaling enabled by default.由于上次的非正常关闭导致的,删掉上次的lock就好

启动shell

mongo 127.0.0.1:27017/admin

创建数据库:use foobar:只有加入list才会真正被创建;查看所有数据库:show dbs

查看所有文档:show collections

添加集合:db.persons.insert({name,'sfp'});mongodb会自动创建一个_id,生成集合system.indexes

查看指定文档的数据:db.persons.find();db.persons.findOne();

更新:db.persons.update({name:'sfp'},{name,'sfp1'}):查询器,修改器

   另一种方式:var p=db.persons.findOne(); db.persons.update(p,{name,'sfp1'});这种更新内容是正常的

                                   {age,'1'};更新后的文档只有age,所以才需要$set修改器

删除:db.persons.remove({})

02

删除集合:db.persons.drop()

删除数据库:db.dropDatebase()

全局help,数据库db.help(),集合db.persons.help()

命名的特殊情况:集合名(db-text),只能通过db.getCollection('db-text')得到此集合。

API:http://api.mongodb.org/js/2.7.7/ 

 03

主要是讲增,删,改。

insert:可以手动加_id

批量插入:如果用[{},{}],则会插入一个文档,用0,1索引对应的{}。所以需要使用for循环来批量插入

save:与insert的区别,id相同时,save会变为更新语句,而insert会报错

db.persons.remove({}):集合被删除,索引不会被删除

数据量特别大的集合:drop再建索引,比remove效率高。如何为集合建立索引? 

强硬文档替换式更新操作:文档替换;id冲突时会报错(原id有3,把id为2的改为3,则报错)

({},{},true):找不到,insert文档;能找到,update文档

({},{},false,true):批量更新,修改器需使用$set

修改器

$set 有这个键,更新;没有这个键,添加。
$inc 数字域,{age:27},{$inc:{age:1}}
$unset 去掉某个键,{age:27},{$uninc:{age":1}}
$push 数组键,1、给指定的数组键增加一个新的数值;2、如果不存在指定的数组键,则新建数组键;3、如果指定的不是数组键,则中断
$pushAll 批量插入
$addToSet 数组中存在要加的值,则忽略;不存在,则增加
$pop 删除数组中指定的值,1:最后一个;-1:第一个
$pull 删除数组中指定的值
$pullAll 批量删除
$ 数组定位器,{“books.type”:"js"},{$set:{"books.$.author":"uspcat"}}

$addToSet和$each:批量更新数组,{$addToSet:{books:{$each:["js","db"]}}}

04

一个document创建后,会分配一定内存,会预留一部分内存。在预留的内存中修改时比较快;在未分配的内存中修改时比较慢。

runCommend:执行mongoDB的特殊函数

findAndModify:返回update或remove的文档

05

主要讲find,分页与排序,游标

返回指定的键:db.persons.find({},{_id:0,name:1,country:1});         _id默认返回,所以需要指定为0,不反回

查询条件:$lt,$lte,$gt,$gte,$ne

1、年龄在25-27之间:age:{$gte:25,$lte:27}

2、不是韩国学生的数学成绩:({cuntry:{$ne:korea}},{m:1})

包含$in,不包含$nin(只针对数组有效)

3、中国或美国:country:{$in:["china","us"]}

$or

4、语文高于85或英语高于90:$or:[{c:{$gt:85}},{e:{$gt:90}}]

5、正则查询,名字中包含li的:name:{/li/i}

$not(范围广,不局限于数组)

6、名字中没有li的:name:{$not:/li/i}

$all,index

7、喜欢mongodb,js的学生:books.{$all:["js","mongodb"]}

8、喜欢的第二本书是Java:"books.1":"java"

$size:不能与比较符一起使用(不足)

9、书为四本的学生:books:{$size:4}

10、数量大于3本的学生:由于$size的不足,所以需要三步

  1、加size字段:{$set:{size:4}},false,true:批量增加字段

  2、改变书籍的更新方式:{$push:{books:"oracle"},$inc:{size:1}}

  3、利用$gt查询

11、喜欢书的数量:

1
2
3
4
5
var jim=db.persons.find({name:"jim"});   //得到的jim是游标,所以需要以下处理。在具体情况中,可以试验一下用数组可以不?返回的应该是数组。
while(jim.hasNext()){
    var obj=jim.next();
    print(obj.books.length);
}<br>

$lt,$lte,$gt,$gte,$ne,$or,$not,$all,$size

06

$slice:返回指定数组的内部值

12、2-4本书:books:{$slice:[1,3]}

$elemMatch:文档查询:对象嵌套

13、在K上过学:school:{school:"K",score:"A"},需要完全匹配;顺序也需要一致

  解决办法:"school.score":"A","school.school":"K"  或者  也可以只写一个 "school.school":"K"

  新问题:school:A,score:D,也会有结果。

  解决办法:school:{$elemMath:{school:"K",score:"A"}}

$where:万能,性能低

14、年龄大于22,喜欢Java,在K上过学:find($("where"):function(){}),跟Java中的查询类似

$slice,$elemMatch,$where.

分页与排序

查前5:find().limit(5)

跨越5条:find().limit(5).skip(5)

排序:find().limit(5).skip(5).sort({name:1}),1为正序,-1为倒序

skip性能有问题---换种方式---加date字段,一般来说skip就够了。

游标

销毁条件:1、迭代完;2、客户端命令;3、10分钟不用。

快照

find({,$snapshot:true}),使用快照,则需使用高级查询。

如果不用快照的话,游标到了3,如果加了100个键,增大,则会把3放在最后,且扩容,把4变为3

用快照的话,不会发生以上的情况

高级查询

$query, $orderby, $maxsan, $min, $max, $hint, $explain, $snapshot

07

索引,管理,空间索引

索引(目录)

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

提高查询性能,影响插入性能,查多插少可考虑索引;索引不一定提高性能;排序也可加索引。

唯一索引:{unique:true}

建唯一索引前已有重复值:{dropDups:true}

本次查询指定索引:.hint({name:1})

管理

查看本次查询的信息:explain()

数据库中所有的索引:db.system.indexes.find();  或者  db.system.namespace.find()

因为建索引会锁表,所以需要让索引在后台创建:{background:true}

删除索引:精确删除:db.runCommand({dropIndexes:'books',index:'name_1'});批量删除:db.runCommand({dropIndexes:'books',index:'*'}) 

08

空间索引

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

距离最近:db.map.find({gis:{$near:[70,180]}}).limit(3)

方形内:db.map.find({gis:{$within:{$box:[[50,50],[190,190]]}}})

圆形内:db.map.find({gis:{$within:{$center:[[50,50],[190,190]]}}})

09 

count+distinct+group,命令操作,固定集合,gridFs文件系统,服务器端脚本

count

1、查询美国学生人数:find({country:"usa"}).count()

distinct

2、有多少国家分别是什么:runCommand({distinct:"persons",key:"country"}).value(),去重

group

3、persons中每个国家学生数学成绩最好的学生,必须在90以上

1
2
3
4
5
6
7
8
9
10
<span style="font-size: 16px;">runCommand({group:{
   ns:"persons",    //集合名
   key:{"country":true},   //分组的键
   initial:{m:0},   //初始化累加器
   $reduce:function(doc,perv){},   //每个文档执行reduce方法,(组内本条记录,累加器数据)
   condition:{m:{$gt:90}},   //条件
   finalize:function(){},   //完成器,把每个人的信息链接起来写一个描述赋值到m上。
    }
})
</span>

4、如果有键country和counTry,则需

1
2
3
4
<span style="font-size: 16px;">$keyf:function(doc){
   return {country:doc.counTry}          //reduce函数也需要改一下,
}
</span>

命令操作

删除list:db.runCommand({drop:"map"});

查询runCommand能够执行的所有命令:db.listCommands();(http://chenzhou123520.iteye.com/blog/1629946)

10

固定集合:固定的大小和文档数

特性:1、没索引,没_id;2、插入块,查询快;3、适合日志

创建大小100字节,存10个文档:db.createColllection("mycoll",{size:100,capped:true,max:10})

普通集合转固定集合:db.runCommand({convertToCapped:"persons",size:100})

反向排序:db.mycoll.find().sort({$natural:-1})

尾部游标(shell不支持,Java,php支持):不会自动销毁,等待结果

GridFS:把本地文件存入mongoDB,使用mongofiles.exe

上传:mongofiles -d foobar -l "e:\a.txt" put "a.txt"

查询:db.fs.chunks.find();   或者  db.fs.files.find()

查看文件内容(VUE,shell不行):mongofiles -d foobar get "a.txt"

查看所有文件:mongofiles -d foobar list

删除文件(VUE,shell不行):mongofiles -d foobar delete "a.txt"

服务器端的脚本:主要讲的是shell中可以使用eval函数:db.eval("function(name){return name}","uspcat");

写入全局变量:db.system.js.insert({_id:name,value:"uspcat"});  db.eval("return name");

进而可以演变为存储方法:把"uspcat"写为"function(){}"

11

启动配置;导出,导入,运行时备份;Fsync锁,数据修复;用户管理,安全认证;

启动项:--dbpath; --port; --fork(保护进程的方式启动); --logpath; --config; -auth(安全认证)

利用config启动,并改端口为8888

mongodbconf.bat:mongod.exe --config mongod.conf

mongod.conf:dbpath = d:\data

         port = 8888

启动mongodbconf.bat

停止shell:

1、右键关,不好,下次启动出问题后,把lock删了

2、ctrl+c

3、use admin, db.shutdownServer()

导出

mongoexport -d -c -o -csv -q --type<json/csv/txv>

mongoexport -d foobar -c port -o D:\persons.json

导出其他数据库的:mongoexport --host --port

导入

mongoimport --db foobar --collection persons --file d:\persons.json

运行时备份:

mongodump --host -d -o  (有数据丢失,后面会解决)

恢复:mongorestore --host -d -directoryperdb

12

缓冲池:数据先写入缓冲池,再写入数据库,运行时备份只会备份数据库的,会丢失缓冲池的,所以需要锁

上锁:把缓冲池的数据全部写入数据库:db.runCommand({fsync:1,lock:1})

解锁:db.currentUp()

修复:db.repairDatabase()

用户管理,安全认证

添加用户:db.addUser("uspcat',"123")

需启用用户,才能查询数据库:db.auth("uspcat","123")

非admin用户不能用数据库命令:如show dbs.

删除用户:db.system.users.remove({user,"uspcat"})

13

主从复制,副本集

主从复制:数据库同步备份的集群技术

--master 主;--slave,--source 从

主:dbpath; port; bind_ip; master;

从:dbpath; port; bind_ip; source; slave;

配置好后,在主中写入数据,在从中可以看到。

默认会监听所有的数据库,通过

--only指定需复制的数据库

--slavedelay:同步延迟

--fastsync:把内存中的数据写入主数据库,进行从备份

--autoresync:不同步的重新同步,从才备份

--oplogsize(主):把主的操作记录到oplog,在从中运行一遍

动态添加和删除从的节点

查看:db.sources.find()

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

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

14

副本集

A故障后,B,C中选一个作为活跃,A恢复后,依然为备份。

设置副本集:

 

初始化副本集:

只有活跃点才能查询(rs.status()),备份的不能查询。

新的仲裁方式:备份的时间早的为活跃。

读写分离:slaveOkay:true;  在shell中不行,高级驱动可以

oplog:保存节点操作

主从:2台就可以,副本:3台以上。

15

这节讲的是分片,挺有意思的,自己试一下,综合性很强。

路由监听配置服务器,线画错了。

router.bat:mongos --port 1000 --configdb 127.0.0.1:2000    

peizhi.bat:mongod --config peizhi.conf

peizhi.conf:dbpath = D:\mongodb\config   //不用加""

      port = 2000

      bind_ip = 127.0.0.1

01.bat:mongod --config 01.conf

01.conf:dbpath = D:\mongodb\8081    

    port = 8081

    bind_ip = 127.0.0.1

01_8081.bat:mongo 127.0.0.1:8081/admin

02.bat:mongod --config 02.conf

02.conf:dbpath = D:\mongodb\8082    

    port = 8082

    bind_ip = 127.0.0.1

02_8082.bat:mongo 127.0.0.1:8082/admin

利用路由为集群增加分片:

打开四个bat,打开router的shell。

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

打开数据分片功能,为foobar打开分片功能:

use foobar, insert, db.runCommand({"enablesharding":"foobar"});

对集合进行分片:

db.runCommand({"shardCollection":"foobar.bar","key":{"_id":1}})   //使用数据库foobar中集合bar的key键进行分片

插入数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function add(){
    var i=0;
    for(;i<200000;i++){
        db.bar.insert({"age":i+10, "name":"jim"})
    }
}
 
function add2(){
    var i=0;
    for(;i<200000;i++){
        db.bar.insert({"age":12, "name":"tom"+i})
    }
}
 
function add3(){
    var i=0;
    for(;i<200000;i++){
        db.bar.insert({"age":i+10, "name":"lili"+i})
    }
}

在01和02的shell中可以看到分配的数据。

在路由的shell中,输入db.peintShardingStatus();

在路由的shell中,use config, show dbs,db.shards.find();   //两个片区 db.mongos.find().

that's it!

更多的知识:配置服务器做成集群

片区与副本集结合使用

摘自:http://www.cnblogs.com/wang-jing/p/3975904.html