1、聚合
一、Count
1.一、请查询person中美国学生的人数。
db.person.find({country:"USA"}).count();
二、Distinct
示例:
2.一、请查询出person中一共有多少个国家,分别是什么?
db.runCommand({distinct:"person",key:"country"}).values;
三、Group
语法:
db.runCommand({group:{
ns:集合名字,
key:分组的键对象,
initial:初始化累加器,
$reduce:组分解器,
Condition:条件,
Finalize:组完成器
}})
分组:
首先会按照key进行分组,每组的每个文档全要执行$reduce的方法,
它接收2个参数,一个是组内本条记录,另外一个是累加器数据。
示例:
3.一、请查出person中每一个国家学生数学成绩最好的学生信息(必须在90以上)
db.runCommand({group:{
ns:"person",
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.二、Finalize完成器的使用
示例:
在3.1要求基础之上,把每一个人的信息链接起来,写一个描述赋值给m。
db.runCommand({group:{
ns:"person",
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}},
finalize:function(prev){
prev.m=prev.name+" Math Score "+prev.m
}
}})
3.三、用函数格式化分组的键
若是集合中出现键country和counTry同时存在,分组如何解决?
示例:
准备数据:向person集合插入一条记录(新增一列counTry,注意大小写)
db.person.insert({
name:"USPCAT",
age:25,
email:235642314@qq.com,
c:80,
m:100,
e:85,
counTry:"China",
books:{"JAVA","C#","Oracle"}
});
在3.2的要求基础上,不区分列country大小写进行分组查询。
db.runCommand({group:{
ns:"person",
$keyf:function(doc){
if(doc.country){
return doc.country;
}
else{
return doc.counTry;
}
},
initial:{m:0},
$reduce:function(doc,prev){
if(doc.m>prev.m){
prev.m=doc.m;
prev.name=doc.name;
if(doc.country){
prev.country=doc.country;
}
else{
prev.country=doc.counTry;
}
}
},
condition:{m:{$gt:90}},
finalize:function(prev){
prev.m=prev.name+" Math Score "+prev.m
}
}})
四、MapReduce
count,distinct,group能作的事情MapReduce都能作,它是一个能够轻松并行化到多个服务器的聚合方法。
它会拆分问题,再将各个部分发送到不一样机器上,让每台机器完成一部分.当全部机器都完成时候,再把结果聚集起来造成
最终完整的结果。
MapReduce须要几个步骤:
(1).映射(map):将操做映射到集合中的每一个文档.这个操做要么什么都不作,要么产生一个键和n个值。
(2).洗牌(shuffle):按照键分组,并将产生的键值组成列表放到对应键中。
(3).化简(reduce):把列表中的值 化简 成一个单值,这个值被返回。
(4).从新洗牌(reshuffle):直到每一个键的列表只有一个值为止,这个值就是最终结果。
MapReduce的速度比group慢,group也很慢.在应用程序中,最好不要用MapReduce,能够在后台运行MapReduce
建立一个保存结果的集合,能够对这个集合进行实时查询。
示例:
4.一、找出集合中的全部键
MongoDB没有模式,因此并不知晓每一个文档有多少个键,一般找到集合的全部键的作好方式是用MapReduce。
在映射阶段,想获得文档中的每一个键,map函数使用emit 返回要处理的值。emit会给MapReduce一个键和一个值。
这里用emit将文档某个键的记数(count),返回({count:1})。咱们为每一个键单独记数,因此为文档中的每个键调用一次emit,
this是当前文档的引用:
map=function(){
for(var key in this)
{
emit(key,{count:1})
}
};javascript
这样返回了许许多多的{count:1}文档,每个都与集合中的一个键相关.这种有一个或多个{count:1}文档组成的数组,
会传递给reduce函数.reduce函数有两个参数,一个是key,也就是emit返回的第一个值,另外一个参数是数组,由一个或者多个
对应键的{count:1}文档组成.
reduce=function(key,emits){
total=0;
for(var i in emits){
total+=emits[i].count;
}
return {count:total};
}
reduce要能被反复被调用,不管是映射环节仍是前一个化简环节.reduce返回的文档必须能做为reduce的
第二个参数的一个元素.如x键映射到了3个文档{"count":1,id:1},{"count":1,id:2},{"count":1,id:3}
其中id键用于区别.MongoDB可能这样调用reduce:
>r1=reduce("x",[{"count":1,id:1},{"count":1,id:2}])
{count:2}
>r2=reduce("x",[{"count":1,id:3}])
{count:1}
>reduce("x",[r1,r2])
{count:3}
reduce应该能处理emit文档和其余reduce结果的各类集合.
如:
mr=db.runCommand(
{
"mapreduce":"user",
"map":map,
"reduce":reduce,
"out":{inline:1}
}
)
或:
db.user.mapReduce(map,reduce,{out:{inline:1}})"timeMillis" : 5,//操做花费的时间
"counts" : {
"input" : 10,//发往到map函数的文档个数
"emit" : 40,//在map函数中emit被调用的次数
"reduce" : 4,//在map函数中reduce被调用的次数
"output" : 4//结果集合中建立的文档数量.
},
(1).mapreduce是根据map函数里调用的emit函数的第一个参数来进行分组的。
(2).仅当根据分组键分组后一个键匹配多个文档,才会将key和文档集合交由reduce函数处理。
注意:MongoDB 1.8版本以上,必须指明 out 参数 。
不然会报以下错误:
"assertion" : "'out' has to be a string or an object",
"assertionCode" : 13606,
MapReduce中的其余键
mapreduce,map,reduce这三个键是必须的,MapReduce命令还有其余的可选键
finalize:函数
将reduce的结果发送给这个键,这是处理过程的最后一步
keeptemp:布尔值
链接关闭时,临时结果是否保存
output:字符串
结果集合的名字,设定该项则隐含着keeptemp:true
query:文档
会在发往map函数前,先用指定条件过滤文档
sort:文档
会在发往map函数前先给文档排序
limit:整数
发往map函数文档的最大数量
scope:文档
javascript代码中要用到的变量
verbose:布尔值
是否产生更加信息的服务器日志 php
2、数据库命令操做
一、命令执行器runCommand
1.一、用命令执行完成一次删除集合的操做
db.runCommand({drop:"person"})
执行结果:
{
"nIndexesWas" : 1,
"msg" : "indexes dropped for collection",
"ns" : "foorbar.person",
"ok" : 1
}
二、如何查询MongoDB为咱们提供的命令
2.一、Mongodb启动命令mongod参数说明:
http://www.uspcat.com/forum.php?mod=viewthread&tid=7722&extra=page%3D1
2.二、在shell中执行db.listCommands();
2.三、访问网址:http://localhost:28017/_commands
(注意:通常状况下,网址端口号在数据库端口号的基础上加1000;启动数据库时,必须开启简单的rest API,才能访问API网址。)
三、经常使用命令示例
3.一、查询服务器版本号和主机操做系统信息。
db.runCommand({buildinfo:1});
3.二、查询执行集合的大小,空间,索引等详细信息。
db.runCommand({collStats:"books"});
3.三、查询操做本集合最后一次的错误信息。
db.runCommand({getLastError:"map"});
返回结果:
{ "n" : 0, "connectionId" : 5, "err" : null, "ok" : 1 }
3、固定集合
一、固定集合的概念:容量大小不会改变的集合。
以下图所示:html
二、固定集合的特性
(1)、若是空间不足,插入新文档时,会自动删除最先的记录;
(2)、在固定集合中,不容许手工删除文档;
(3)、致使文档位置发生变化的更新操做,将会被拒绝;
(4)、默认状况下,固定集合没有索引,"_id"也是没有索引的,固然,索引能够手工建立;
(5)、因为固定集合不须要分配新的空间,因此它的插入速度是很是的快;
(6)、因为固定集合的顺序是肯定的,因此它的查询速度是很是的快;
(7)、最适合的应用就是日志管理。
三、建立固定集合
3.一、建立一个新的固定集合,要求:大小是100字节,能够存储10个文档。
db.createCollection("my_collection",{size:100,capped:true,max:10});
3.二、把一个普通集合转换成固定集合
db.runCommand({convertToCapped:"person",size:100000});
四、天然排序(文档在磁盘上的物理排序)
$natural取值为1时,表示与默认顺序相同,取值为-1时,则恰好相反。
4.一、查询固定集合mycollection而且反向排序
db.mycollection.find().sort({$natural:-1});
五、尾部游标(shell不支持,java和php等驱动是支持的)
5.一、尾部游标的概念
这是个特殊的只能用到固定集合上的游标,它在没有结果的时候,
也不会自动销毁,它是一直等待结果的到来。
当关联的集合内有新文档被添加时,尾部游标就会被触发。
5.二、特色:
链接持久化:在明确指定的状况下,不会自动关闭。java
4、GridFS文件系统
一、GridFS文件系统的概念
GridFS是MongoDB提供的用于存储大型二进制数据的机制。
它自己就是一个分布式文件系统:
(1)、GridFS会直接利用已创建的复制、分片机制;
(2)、GridFS能够避免传统文件系统的某些弊端,例如:同一目录下文件数量过多;
(3)、GridFS不会产生磁盘碎片。
二、GridFS文件系统的原理
{"_id":ObjectId("..."),
"n":0,
"data":BinData("..."),
"files_id":ObjectId("...")
}
GridFS是创建在MongoDB普通文档基础之上的轻量级的分布式文件存储规范。
它的基本思想是,将大型文件切分红不少小块,每一块做为一个单独的文档存储。
在GridFS规范中定义了不少额外的键,最值得关注的是md5这个键,利用它能够作不少有趣的事情。
三、使用GridFS
3.一、查看GridFS的全部功能
cmd->mongofiles
3.二、上传一个文件
mongofiles -d foorbar -l "D:\Work\MongoDB\GridFS测试.txt" put "GridFSTest.txt"
3.三、查看GridFS文件的存储状态
利用VUE查看,以下图所示:
集合查看
db.fs.chunks.find()和db.fs.files.find()存储文件系统的全部文件信息。
(1)> db.fs.chunks.find()
{ "_id" : ObjectId("51fe10e7fdf286d0aec9cf1c"), "files_id" : ObjectId("51fe10e7dff0527f1beb1819"), "
n" : 0, "data" : BinData(0,"R3JpZEZTsuLK1EdyaWRGU7LiytRHcmlkRlOy4srUR3JpZEZTsuLK1EdyaWRGU7LiytQ=") }
(2)> db.fs.files.find()
{ "_id" : ObjectId("51fe10e7dff0527f1beb1819"), "chunkSize" : 262144, "filename" : "GridFSTest.txt",
"length" : NumberLong(50), "md5" : "13a8cb2df1be313f2e931ea854f868ab", "uploadDate" : ISODate("2013
-08-04T08:29:27.629Z") }
3.四、查看文件内容( VUE中能够查看,shell没法打开文件)
mongofiles -d foorbar get "GridFSTest.txt"
3.五、查看全部文件
mongofiles -d foorbar list
3.六、删除已经存在的文件(VUE中操做)
mongofiles -d foorbar delete "GridFSTest.txt"
5、服务器端脚本
一、Eval
利用db.eval()能够在MongoDB的服务器端执行任意JavaScript脚本。
用处有不少,好比事务模拟。
重点要提的就是,若是传入的JavaScript脚本过大,会给调试代码不少不便,此时能够将调试信息写入到数据库日志中。
方法是在脚本中调用以下语句:
db.eval("print('Hello World!');")
1.一、服务器端运行eval
db.eval("function(name){return name}","uspcat")
二、Javascript的存储
存储JavaScript就相似于sql数据库中的存储过程。
能够将JavaScript脚本(js变量或者函数)保存在服务器端,须要的时候可使用前面提到的db.eval()调用。
示例:
(1)、把变量加载到特殊集合system.js中;
db.system.js.insert({"_id":"name",value:"uspact"})
(2)、调用
db.eval("return name;");
6、数据库引用(DBREF)
一、语法:
{"$ref":"集合名称","$id":"惟一标识键","$db":"数据库"}
二、概念
DBRef是做为内嵌文档来存在的,它的做用就至关于html标签中a标签的和href特性。
DBRef能够跨数据库引用文档,就如上面的代码演示的那样。
注意:
以上代码中键的顺序是不能改变的,必须是这样的顺序,只有$db键是可选的。
三、示例:
建立一个用户user集合:
建立一个笔记note集合;
笔记能够引用用户或者别的笔记。
(1)、给user集合添加数据
db.user.insert({"_id":"Make","display_name":"Make D"});
db.user.insert({"_id":"Kristina","display_name":"Kristina C"});
(2)、给note集合添加数据
db.note.insert({"_id":5,"author":"Make","text":"MongoDB is fun!"});
db.note.insert({"_id":6,"author":"Kristina","text":"... and DBrefs are easy,too!",
"references":[{"$ref":"user","$id":"Make"},{"$ref":"note","$id":5}]
});
(3)、查询笔记note集合引用的数据
var note=db.note.findOne({"_id":6});
note.references.forEach(function(ref){
printjson(db[ref.$ref].findOne({"_id":ref.$id}));
});
执行结果:
{ "_id" : "Make", "display_name" : "Make D" }
{ "_id" : 5, "author" : "Make", "text" : "MongoDB is fun!" }
sql