mongoDB并不是关系型数据库,而是像一种对象型数据库,用Json格式来存放对象 没有oracle很多表之间的关联, 基本上一个对象内的所有属性都在一条记录中, 对象中的集合是用数组的形式来表现,所以会有很强调对数组的操作。 mongoDB的分片,分布式数据库 -------CMD title小技巧--------------- 在cmd文件的第一行输入 title wsrp at port:7002, debug port 5557 ------使用数据库------ use tristan ------查看数据库信息------ show dbs show collections db.help() db.person.help() ------插入数据------ db.person.insert({"name":"tristan","age":"29","habbit":"guitar,stock"}) ---key可以不带""--- db.person.insert({name:"tristan",age:"29",habbit:"guitar,stock"}) save() --如果_id已有则更新 db.person.save({_id:99,name:"tristan",age:"29",habbit:"guitar,stock"}) ---循环插入数据--- for(var i=0;i<10000;i++){ db.person.insert({_id:i,name:"tristan"+i,age:29,habbit:"guitar,stock"}); } -------查看数据------- db.person.find({name:"tristan99"}) db.person.find(...).count() db.person.find(...).limit(n) db.person.find(...).skip(n) db.person.find(...).sort(...) ---查询条件--- find({条件},{查询指定键}) db.persons.find({},{_id:0,name:1,age:1,country:1}) $lt < $lte <= $gt > $gte >= $ne != AND查询 2.1查询出年龄在25到26岁之间的学生 db.persons.find({age:{$gte:25,$lte:26}},{_id:0,name:1,age:1,country:1}) 2.2查询出所有不是韩国籍的学生的数学成绩 db.persons.find({country:{$ne:"Korea"}},{_id:0,name:1,age:1,country:1}) 包含或不包含 $in或$nin 2.3查询国籍是中国或美国的学生信息 db.persons.find({country:{$in:["USA","China"]}},{_id:0,name:1,age:1,country:1}) 2.4查询国籍不是中国或美国的学生信息 db.persons.find({country:{$nin:["USA","China"]}},{_id:0,name:1,age:1,country:1}) OR查询 2.4查询语文成绩大于85或者英语大于90的学生信息 db.persons.find({$or:[{c:{$gte:85}},{e:{$gte:90}}]},{_id:0,name:1,age:1,country:1, c:1,e:1}) NULL 把中国国籍的学生上增加新的键sex db.persons.update({country:"China"},{$set:{sex:"m"}},false, true) 2.5查询出sex 等于 null的学生 db.persons.find({sex:{$in:[null]}},{country:1}) 正则查询 2.6查询出名字中存在"li"的学生的信息 db.persons.find({name:/li/i},{_id:0,name:1}) $not的使用 $not可以用到任何地方进行取反操作 2.7查询出名字中不存在"li"的学生的信息 db.persons.find({name:{$not:/li/i}},{_id:0,name:1}) $not和$nin的区别是$not可以用在任何地方儿$nin是用到集合上的 数组查询$all和index应用 2.8查询喜欢看MONGOD和JS的学生 db.persons.find({books:{$all:["MONGODB","JS","JAVA"]}},{books:1,_id:0}) 2.9查询第二本书是JAVA的学习信息 db.persons.find({"books.1":"JAVA"}) 查询指定长度数组$size它不能与比较查询符一起使用(这是弊端) 2.8查询出喜欢的书籍数量是4本的学生 db.persons.find({books:{$size:4}},{_id:0,books:1}) 文档查询 【子对象查询】 为jim添加学习简历文档 jim.json 2.13查询出在K上过学的学生 1. 这个我们用绝对匹配可以完成,但是有些问题(找找问题?顺序?总要带着score?) db.persons.find({school:{school:"K",score:"A"}},{_id:0,school:1}) 2.为了解决顺序的问题我可以用对象"."的方式定位 db.persons.find({"school.score":"A","school.school":"K"},{_id:0,school:1}) 3.这样也问题看例子: db.persons.find({"school.score":"A","school.school":"J"},{_id:0,school:1}) 同样能查出刚才那条数据,原因是score和school会去其他对象对比 4.正确做法单条条件组查询$elemMatch db.persons.find({school:{$elemMatch:{school:"K",score:"A"}}}) .$where 12.查询年龄大于22岁,喜欢看C++书,在K学校上过学的学生信息 复杂的查询我们就可以用$where因为他是万能 但是我们要尽量避免少使用它因为他会有性能的代价 db.persons.find({"$where":function(){ var e = this.e; var c = this.c; if(e > 80 & c > 80){ return true; } }},{_id:0,name:1}) -------分页与排序---------- 1.Limit返回指定的数据条数 1.1查询出persons文档中前5条数据 db.persons.find({},{_id:0,name:1}).limit(5) 2.Skip返回指定数据的跨度 2.1查询出persons文档中5~10条的数据 db.persons.find({},{_id:0,name:1}).limit(5).skip(5) 3.Sort返回按照年龄排序的数据[1,-1] db.persons.find({},{_id:0,name:1,age:1}).sort({age:1}) 注意:mongodb的key可以存不同类型的数据排序就也有优先级 4.Limit和Skip完成分页 4.1三条数据位一页进行分页 第一页?db.persons.find({},{_id:0,name:1}).limit(3).skip(0) 第二页?db.persons.find({},{_id:0,name:1}).limit(3).skip(3) 4.2skip有性能问题,没有特殊情况下我们也可以换个思路 对文档进行重新解构设计 每次查询操作的时候前后台传值全要把上次的最后一个文档的日期保存下来 db.persons.find({date:{$gt:日期数值}}).limit(3) 个人建议-->应该把软件的中点放到便捷和精确查询上而不是分页的性能上 因为用户最多不会翻查过2页的 -------游标【直接操作查询结果】,快照---------- 利用游标遍历查询数据 var persons = db.persons.find(); while(persons.hasNext()){ obj = persons.next(); print(obj.name) } 查询快照 快照后就会针对不变的集合进行游标运动了,看看使用方法. db.persons.find({$query:{name:”Jim”},$snapshot:true}) --------索引---------- 初始数据 for(var i = 0 ; i<200000 ;i++){ db.books.insert({number:i,name:i+"book"}) } var start = new Date() db.books.find({number:65871}) var end = new Date() end - start --102秒 建立索引 db.books.ensureIndex({number:1}) --12秒 索引使用需要注意的地方 1.创建索引的时候注意1是正序创建索引-1是倒序创建索引 2.索引的创建在提高查询性能的同事会影响插入的性能 对于经常查询少插入的文档可以考虑用索引 3.符合索引要注意索引的先后顺序 4.每个键全建立索引不一定就能提高性能呢 索引不是万能的 5.在做排序工作的时候如果是超大数据量也可以考虑加上索引 用来提高排序的性能 db.books.ensureIndex({number:1}) 创建索引同时指定索引的名字 db.books.ensureIndex({name:-1},{name:"bookname"}) 唯一索引 4.1如何解决文档books不能插入重复的数值 建立唯一索引 db.books.ensureIndex({name:-1},{unique:true}) 试验 db.books .insert({name:"1book"}) Hint 6.1如何强制查询使用指定的索引呢? db.books.find({name:"1book",number:1}).hint({name:-1}) 指定索引必须是已经创建了的索引 Expain 7.1如何详细查看本次查询使用那个索引和查询数据的状态信息 db.books.find({name:"1book"}).explain() 在shell查看数据库已经建立的索引 db.system.indexes.find() db.system.namespaces.find() 批量和精确删除索引 db.runCommand({dropIndexes : ”books” , index:”name_-1”}) db.runCommand({dropIndexes : ”books” , index:”*”}) ------二维索引---------- map.json 1.查询出距离点(70,180)最近的3个点 添加2D索引 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}) ----------聚合------------- 1.Count 请查询persons中美国学生的人数. db.persons.find({country:"USA"}).count() 2.Distinct 请查询出persons中一共有多少个国家分别是什么. db.runCommand({distinct:"persons" , key:"country"}).values 3.Group 语法: db.runCommand({group:{ ns:集合名字, Key:分组的键对象, Initial:初始化累加器, $reduce:组分解器, Condition:条件, Finalize:组完成器 }}) 分组首先会按照key进行分组,每组的 每一个文档全要执行$reduce的方法, 他接收2个参数一个是组内本条记录,一个是累加器数据. 3.1请查出persons中每个国家学生数学成绩最好的学生信息(必须在90以上) db.runCommand({group:{ ns:"persons", key:{"country":true}, initial:{m:0}, $reduce:function(doc,prev){ if(doc.m > prev.m){ prev.m = doc.m; prev.name = doc.name; prev.country = doc.country; } }, condition:{m:{$gt:90}} }})
3.2在3.1要求基础之上吧没个人的信息链接起来写一个描述赋值到m上 finalize:function(prev){ prev.m = prev.name+" Math scores "+prev.m } -------------固定集合----------------- 固定特性 2.1固定集合默认是没有索引的就算是_id也是没有索引的 2.2由于不需分配新的空间他的插入速度是非常快的 2.3固定集合的顺是确定的导致查询速度是非常快的 2.4最适合的是应用就是日志管理 创建固定集合 3.1创建一个新的固定集合要求大小是100个字节,可以存储文档10个 db.createCollection("mycoll",{size:100,capped:true,max:10}) 3.2把一个普通集合转换成固定集合 db.runCommand({convertToCapped:”persons”,size:100000}) -------------GridFS文件系统------------------ GridFS是mongoDB自带的文件系统他用二进制的形式存储文件 大型文件系统的绝大多是特性GridFS全可以完成 在cmd下运行, 而不是mongo环境 mongofiles --dbpath E:\mongodb\data2 -d tristan -l "E:\mongodb\gridfs\a.txt" put "b.txt" 【shell不成功 可以用VUE】 -------------服务器端脚本--------------- 1.1服务器端运行eval db.eval("function(name){ return 'hello ' + name}","uspcat") 2.Javascript的存储 【类似于Oracle的存储过程】 2.1在服务上保存js变量活着函数共全局调用 1.把变量加载到特殊集合system.js中 db.system.js.insert({_id:"name",value:"uspcat"}) 2.调用 db.eval("return name;") System.js相当于Oracle中的存储过程,因为value不单单可以写变量 还可以写函数体也就是javascript代码 -------更新数据-------- ---整体更新【更新整条记录】--- db.person.update({age:29}, {habbit:"st jude"}); --只更新第一个文档 var p = db.person.findOne({name:"tristan97"}); p.habbit="st jude"; db.person.update({name:"tristan97"}, p); ---局部更新【更新某个字段】--- db.person.update({name:"tristan99"}, {"$set":{habbit:"st jude"}}) db.person.update({_id:99}, {"$inc":{age:1}}) db.person.update({_id:99}, {"$unset":{age:1}}) --数组操作-- db.person.update({_id:99}, {"$pushAll":{habbit:["1","2","3"]}}) db.person.update({_id:99}, {"$addToSet":{habbit:["1","2","3"]}}) $pop, $pull, $pullAll, $【数组定位器】, $each ---findAndModify【不能批量更新】--- 用于返回update或是remove后的文档 ps = db.runCommand({ "findAndModify":"person", "query":{name:"tristan51"}, "update":{$set:{age:100}}, "new":true }) ps.value ---更新多个文档---- db.person.update({age:29}, {$set:{habbit:"st jude"}}, false, true); --第三个参数 如果找不到就插入 db.runCommand({getLastError:1}) ------删除------ db.person.remove({_id:11}) db.person.drop() db.dropDatabase() -----导入导出-------- 1.导出数据(中断其他操作) 打开CMD 利用mongoexport -d 指明使用的库 -c 指明要导出的表 -o 指明要导出的文件名 -csv 制定导出的csv格式 -q 过滤导出 --type <json|csv|tsv> 1.1把数据好foobar中的persons导出 mongoexport -d tristan -c persons -o D:/persons.json 1.2导出其他主机数据库的文档 mongoexport --host 192.168.0.16 --port 37017 2.导入数据(中断其他操作) API http://cn.docs./manual/reference/mongoimport/ 2.1到入persons文件 mongoimport --db tristan --collection persons --file d:/persons.json 1.运行时备份mongodump API http://cn.docs./manual/reference/mongodump/ 1.1导出127.0.0.1服务下的27017下的foobar数据库 mongodump --host 127.0.0.1:27017 -d tristan -o e:/tristan 2.运行时恢复mongorestore API http://cn.docs./manual/reference/mongorestore/ 2.1删除原本的数据库用刚才导出的数据库恢复 db.dropDatabase() mongorestore --host 127.0.0.1:27017 -d foobar -directoryperdb d:/foobar/foobar 3.懒人备份 mongoDB是文件数据库这其实就可以用拷贝文件的方式进行备份 ----------Fsync锁,数据修复----------- 上锁可以叫缓存池的数据全部进到数据库,这在数据库备份的时候很有意义. 上锁 db.runCommand({fsync:1,lock:1}); 解锁 db.currentOp() 数据修复 当停电等不可逆转灾难来临的时候,由于mongodb的存储结构导致 会产生垃圾数据,在数据恢复以后这垃圾数据依然存在,这是数据库 提供一个自我修复的能力.使用起来很简单 db.repairDatabase() ---------------用户权限-------------------- 1.添加一个用户 1.1为admin添加uspcat用户和foobar数据库的yunfengcheng用户 use admin db.addUser("uspcat","123"); use foobar db.addUser("yunfengcheng","123"); 2.启用用户 db.auth("名称","密码") 3.安全检查 --auth 非foobar是不能操作数据库的 ----------------主从复制【手动HA】----------------- 主从复制是一个简单的数据库同步备份的集群技术 1.1在数据库集群中要明确的知道谁是主服务器,主服务器只有一台. 1.2从服务器要知道自己的数据源也就是对于的主服务是谁. 1.3--master用来确定主服务器,--slave 和 –source 来控制曾服务器 dbpath = D:\sortware\mongod\01\8888 主数据库地址 port = 8888 主数据库端口号 bind_ip = 127.0.0.1 主数据库所在服务器 master = true 确定我是主服务器 dbpath = D:\sortware\mongod\01\7777 从数据库地址 port = 7777 从数据库端口号 bind_ip = 127.0.0.1 从数据库所在服务器 source = 127.0.0.1:8888 确定我数据库端口 slave = true 确定自己是从服务器 2.主从复制的其他设置项 --only 从节点?指定复制某个数据库,默认是复制全部数据库 --slavedelay 从节点?设置主数据库同步数据的延迟(单位是秒) --fastsync 从节点?以主数据库的节点快照为节点启动从数据库 --autoresync 从节点?如果不同步则从新同步数据库 --oplogSize 主节点?设置oplog的大小(主节点操作记录存储到local的oplog中) ----------------副本集【HA】----------------- 1.1第一张图表明A是活跃的B和C是用于备份的 1.2第二张图当A出现了故障,这时候集群根据权重算法推选出B为活跃的数据库 1.3第三张图当A恢复后他自动又会变为备份数据库 -----------------分片【负载技术,分布式架构】------------------------ 路由(1000)-配置服务器(2000)-片区01(8081)-片区02(8082) 路由监听配置 mongos --port 1000 --configdb 127.0.0.1:2000 3.什么时候用到分片呢? 3.1机器的磁盘空间不足 3.2单个的mongoDB服务器已经不能满足大量的插入操作 3.3想通过把大数据放到内存中来提高性能 4.分片步骤 4.1创建一个配置服务器 4.2创建路由服务器,并且连接配置服务器 路由器是调用mongos命令 4.3添加2个分片数据库 8081和8082 4.5利用路由为集群添加分片(允许本地访问) db.runCommand({addshard:"127.0.0.1:8081",allowLocal:true}) db.runCommand({addshard:"127.0.0.1:8082",allowLocal:true}) 切记之前不能使用任何数据库语句 4.6打开数据分片功能,为数据库foobar打开分片功能 db.runCommand({"enablesharding":"foobar"}) 4.7对集合进行分片 db.runCommand({"shardcollection":"foobar.bar","key":{"_id":1}}) 4.8利用大数据量进行测试 (800000条) 5.查看配置库对于分片服务器的配置存储 db.printShardingStatus() 6.查看集群对bar的自动分片机制配置信息 mongos> db.shards.find() { "_id" : "shard0000", "host" : "127.0.0.1:8081" } { "_id" : "shard0001", "host" : "127.0.0.1:8082" } 8.分片与副本集一起使用 -------------MapReduce---------------- book1 = {name : "Understanding JAVA", pages : 100} book2 = {name : "Understanding JSON", pages : 200} db.books.save(book1) db.books.save(book2) book = {name : "Understanding XML", pages : 300} db.books.save(book) book = {name : "Understanding Web Services", pages : 400} db.books.save(book) book = {name : "Understanding Axis2", pages : 150} db.books.save(book) 编写 Map 函数 接下来我们编写一个搜索功能,用来查找超过250页的图书: var map = function() { var category; if ( this.pages >= 250 ) category = 'Big Books'; else category = "Small Books"; emit(category, {name: this.name}); }; 所返回的结果: {"Big Books",[{name: "Understanding XML"}, {name : "Understanding Web Services"}]); {"Small Books",[{name: "Understanding JAVA"}, {name : "Understanding JSON"},{name: "Understanding Axis2"}]); 编写 Reduce 函数 var reduce = function(key, values) { var sum = 0; values.forEach(function(doc) { sum += 1; }); return {books: sum}; }; 在 books 集合中运行 MapReduce var count = db.books.mapReduce(map, reduce, {out: "book_results"}); db[count.result].find() { "_id" : "Big Books", "value" : { "books" : 2 } } { "_id" : "Small Books", "value" : { "books" : 3 } } -------------------------- 上述例子如果用普通的语句,很方便能实现其功能。 db.books.find({pages:{$gt:250}}).count() MapReduce是类似于一种算法 下面是Java实现的MapReduce
引用【MongoDB实战.pdf】 MongoDB 的MapReduce 相当于Mysql 中的"group by",所以在MongoDB 上使用 Map/Reduce进行并行"统计"很容易。 使用MapReduce 要实现两个函数 Map 函数和Reduce 函数,Map 函数调用emit(key, value), 遍历collection中所有的记录,将key与value传递给Reduce 函数进行处理。 Map函数和Reduce函数可以使用JavaScript 来实现,可以通过db.runCommand 或mapReduce 命令来执行一个MapReduce 的操作: |
|