mongoDB

-------mongoDB 和oracle的区别-------------
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}}
}})

db.persons.group({
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;
}
}})


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.mongodb.org/manual/reference/mongoimport/
2.1到入persons文件
mongoimport --db tristan --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 tristan -o e:/tristan
2.运行时恢复mongorestore
API
http://cn.docs.mongodb.org/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
public class TestMapReduce {
public static void main(String[] args) {
Map<String, Integer> map1 = new HashMap<String, Integer>();
map1.put("key1",5);
map1.put("key2",4);
map1.put("key3",14);
map1.put("key4",556);
map1.put("key5",77);

Map<String, Integer> map2 = new HashMap<String, Integer>();
map2.put("key1",78);
map2.put("key2",55);
map2.put("key3",77);
map2.put("key4",765);
map2.put("key5",11);

Map<String, Integer> map3 = new HashMap<String, Integer>();
map3.put("key1",11);
map3.put("key2",22);
map3.put("key3",44);
map3.put("key4",55);
map3.put("key5",66);

//reduce
Map<String, Integer> result = new HashMap<String, Integer>();
result.put("key1",0);
result.put("key2",0);
result.put("key3",0);
result.put("key4",0);
result.put("key5",0);

for(String k : map1.keySet()){
int v = result.get(k);
v += map1.get(k);
result.put(k, v);
}

for(String k : map2.keySet()){
int v = result.get(k);
v += map2.get(k);
result.put(k, v);
}

for(String k : map3.keySet()){
int v = result.get(k);
v += map3.get(k);
result.put(k, v);
}

for(String k : result.keySet()){
System.out.println(k+" "+result.get(k));
}
}
}



引用【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 的操作:
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值