MongoDB讲解01


MongoDB简介

  • MongoDB是什么
    MongoDB是一个使用C++编写的、开源的、面向文档的NoSQL(Not Only SQL)数据库,也是当前最热门的NoSql数据库之一。
  • NoSQL简介
    NoSQL的意思是“不仅仅是SQL”,是目前流行的“非关系型数据库”的统称。
    常见的NoSQL数据库如:Redis、CouchDB、MongoDB、HBase、Cassandra等
  • 为什么需要NoSQL?
    简单的说,就是为了解决在web2.0时代,出现的三高要求:
    1:对数据库高并发读写的需求
    2:对海量数据的高效率存储和访问的需求
    3:对数据库的高可扩展性和高可用性的需求
    而RDB里面的一些特性,在web2.0里面往往变得不那么重要,比如:
    1:数据库事务一致性
    2:数据库的实时读写
    3:复杂的SQL查询,特别是多表关联查询
    关系型表:tbl_user
    Uuid userId name
    1 u1 zhangsan
    2 u2
    NoSQL:bson
    {“uuid”:1,”userId”:”u1”,”name”:zhangsan}
    {“uuid”:2,”userId”:”u2”,age:13}
  • CAP定理, 又被称作布鲁尔定理(Eric Brewer)
    它指出对于一个分布式计算系统来说,不可能同时满足以下三点:
    1:强一致性(Consistency):系统在执行过某项操作后仍然处于一致的,在分布式系统中,更新操作执行成功后所有的用户都应该读取到最新的值,这样的系统被认为具有强一致性
    2:可用性(Availability):每一个操作总是能够在一定的时间内返回结果
    3:分区容错性(Partition tolerance):系统在存在网络分区的情况下仍然可以接受请求并处理,这里网络分区是指由于某种原因网络被分成若干个孤立区域,而区域之间互不相通
  • 根据CAP原理将数据库分成了满足CA原则、满足CP原则和满足AP原则三大类:
    1:CA:单点集群,满足一致性,可用性,通常在可扩展性上不太强大,比如RDB
    2:CP:满足一致性和分区容错性,通常性能不是特别高,如分布式数据库
    3:AP:满足可用性和分区容错性,通常可能对一致性要求低一些,如大多数的NoSQL
  • BASE(Basically Available,Soft-state,Eventual consistency )
    1:基本可用(Basically Available):系统能够基本运行、一直提供服务。
  • NoSQL的优点
    扩展简单方便,尤其是水平横向扩展
    (纵向扩展是指用更强的机器;横向扩展是指把数据分散到多个机器)
    读写快速高效,多数都会映射到内存操作
    成本低廉,用普通机器,分布式集群即可
    数据模型灵活,没有固定的数据模型
    -NoSQL的缺点
    不提供对SQL的支持
    现有产品还不够成熟稳定,功能也还有待加强
    -MongoDB特点
    高性能、易于使用、易于扩展、功能丰富
    面向集合存储,模式自由
    支持动态查询,支持javascript表达式查询
    支持索引
    支持副本集复制和自动故障恢复
    自动处理分片
    支持二进制和大型对象数据
    文件存储格式为BSON(JSON的一种扩展)

MongoDB安装和基本使用

  • 安装
    1:去官方下载最新的包,http://www.mongodb.org/downloads
    2:然后tar zvxf 解压
    3:拷贝到相应的文件夹即可
    注意,奇数版是开发版
  • 在Shell里面启动
    1:在MongoDB的文件夹下创建dbs和logs的文件夹
    2:到bin下,运行 ./mongod –dbpath ../dbs,就可以启动数据库了
    当然,也可以通过 –logpath 来指定日志文件的路径,需要指定到文件。
    3:可以把启动的参数设置到一个配置文件中,然后在启动的时候通过-f进行指定
    4:MongoDB默认会监听27017端口,可以通过 –port来指定主端口
    5:可以通过 ./mongod –help来查看启动时可以指定的参数
  • 在后台启动
    使用–fork选项,将会通知mongodb在后台运行。也可以配置到文件里面去,设置fork=true即可
  • 关闭
    1:如果是在Shell里面启动的,ctrl+c退出shell就关闭了
    2:如果是在后台启动的,运行 pkill mongod
    3:也可以进入javascript shell,切换到admin数据库,运行db.shutdownServer()
    #MongoDB启动参数说明
  • 基本配置
    –quiet # 安静输出
    –port arg # 指定服务端口号,默认端口27017
    –bind_ip arg # 绑定服务IP,若绑定127.0.0.1,则只能本机访问,不指定默认本地所有IP
    –logpath arg # 指定MongoDB日志文件,注意是指定文件不是目录
    –logappend # 使用追加的方式写日志
    –pidfilepath arg # PID File 的完整路径,如果没有设置,则没有PID文件
    –keyFile arg # 集群的私钥的完整路径,只对于Replica Set 架构有效
    –unixSocketPrefix arg # UNIX域套接字替代目录,(默认为 /tmp)
    –fork # 以守护进程的方式运行MongoDB,创建服务器进程
    –auth # 启用验证
    –cpu # 定期显示CPU的CPU利用率和iowait
    –dbpath arg # 指定数据库路径
    –diaglog arg # diaglog选项 0=off 1=W 2=R 3=both 7=W+some reads
    –directoryperdb # 设置每个数据库将被保存在一个单独的目录
    –journal # 启用日志选项,MongoDB的数据操作将会写入到journal文件夹的文件里
    –journalOptions arg # 启用日志诊断选项
    –ipv6 # 启用IPv6选项
    –jsonp # 允许JSONP形式通过HTTP访问(有安全影响)
    –maxConns arg # 最大同时连接数 默认2000
    –noauth # 不启用验证
    –nohttpinterface # 关闭http接口,默认关闭2
    –noprealloc # 禁用数据文件预分配(往往影响性能)
    –noscripting # 禁用脚本引擎
    –notablescan # 不允许表扫描
    –nounixsocket # 禁用Unix套接字监听
    –nssize arg (=16) # 设置信数据库.ns文件大小(MB)
    –objcheck # 在收到客户数据,检查的有效性,
    –profile arg # 档案参数 0=off 1=slow, 2=all
    –quota # 限制每个数据库的文件数,设置默认为8
    –quotaFiles arg # number of files allower per db, requires –quota
    –rest # 开启简单的rest API
    –repair # 修复所有数据库run repair on all dbs
    –repairpath arg # 修复库生成的文件的目录,默认为目录名称dbpath
    –slowms arg (=100) # value of slow for profile and console log
    –smallfiles # 使用较小的默认文件
    –syncdelay arg (=60) # 数据写入磁盘的时间秒数(0=never,不推荐)
    –sysinfo # 打印一些诊断系统信息
    –upgrade # 如果需要升级数据库
  • Replicaton 参数
    –fastsync # 从一个dbpath里启用从库复制服务,该dbpath的数据库是主库的快照,可用于快速启用同步
    –autoresync # 如果从库与主库同步数据差得多,自动重新同步,
    –oplogSize arg # 设置oplog的大小(MB)
    ● 主/从参数
    –master # 主库模式
    –slave # 从库模式
    –source arg # 从库 端口号
    –only arg # 指定单一的数据库复制
    –slavedelay arg # 设置从库同步主库的延迟时间
  • Replica set(副本集)选项:
    –replSet arg # 设置副本集名称
    ● Sharding(分片)选项
    –configsvr # 声明这是一个集群的config服务,默认端口27019,默认目录
    /data/configdb
    –shardsvr # 声明这是一个集群的分片,默认端口27018
    –noMoveParanoia # 关闭偏执为moveChunk数据保存

MongoDB基本概念

  • 数据库
    MongoDB的一个实例可以拥有一个或多个相互独立的数据库,每个数据库都有自己的集合
  • 集合
    集合可以看作是拥有动态模式的表
  • 文档
    文档是MongoDB中基本的数据单元,类似于RDB的行。
    文档是键值对的一个有序集合。在JS中,文档被表示成对象。
  • _id
    每个文档都有个特殊的“_id”,在文档所属集合中是唯一的
  • JavaScript shell
    MongoDB自带了一个功能强大的JavaScript Shell,可以用于管理或操作MongoDB
  • MongoDB和RDB的一些对比
    1:都有数据库的概念
    2:集合 –〉RDB的表
    3:文档 –〉RDB表中的一条记录
    4:文档对象里面的 key –〉 RDB表中的字段
    5:文档对象里面的 value–〉 RDB表中字段的值
    6:MongoDB中没有主外键的概念
  • 数据库名称定义规则
    1:不能是空串
    2:不得含有/、\、?、$、空格、空字符等等,基本只能使用ASCII中的字母和数字
    3:区分大小写,建议全部小写
    4:最多为64字节
    5:不得使用保留的数据库名,比如:admin,local,config
    注意:数据库最终会成为文件,数据库名就是文件的名称
  • 集合名称定义规则
    1:不能是空串
    2:不能包含\0字符(空字符),这个字符表示集合名的结束,也不能包含”$”
    3:不能以”system.”开头,这是为系统集合保留的前缀
  • 文档的键的定义规则
    1:不能包含\0字符(空字符),这个字符表示键的结束
    2:“.”和“$”是被保留的,只能在特定环境下用
    3:区分类型,同时也区分大小写
    4:键不能重复
    注意:文档的键值对是有顺序的,相同的键值对如果有不同顺序的话,也是不同的文档
  • MongoDB基本的数据类型
    数据类型 描述 举例
    null 表示空值或者未定义的对象 {“x”:null}
    布尔值 真或者假:true或者false {“x”:true}
    32位整数 shell不支持该类型,默认会转换成64位浮点数,
    也可以使用NumberInt类,比如: {“x”:NumberInt(“3”)}
    64位整数 shell不支持该类型,默认会转换成64位浮点数,
    也可以使用NumberLong类,比如: {“x”:NumberLong(“3”)}
    64位浮点数 shell中的数字就是这一种类型 {“x”:3.14,”y”:3}
    字符串 UTF-8字符串 {“foo”:”bar”}
    符号 shell不支持,shell会将数据库中的符号类型的数据自动转换成字符串
    对象id 文档的12字节的唯一id {“id”: ObjectId()}
    日期 从标准纪元开始的毫秒数 {“date”:new Date()}
    正则表达式 文档中可以包含正则表达式,遵循JavaScript的语法 {“foo”:/foobar/i}
    代码 文档中可以包含JavaScript代码 {“x”:function() {}}
    未定义 undefined {“x”:undefined}
    数组 值的集合或者列表 {“arr”: [“a”,”b”]}
    内嵌文档 文档可以作为文档中某个key的value

MongoDB增删改操作

  • 运行shell,命令:mongo ip:port
  • 显示现有的数据库,命令:show dbs 或者 databases;
  • 显示当前使用的数据库,命令:db
  • 切换当前使用的数据库,命令:use 数据库名称
  • 创建数据库:
    MongoDB没有专门创建数据库的语句,可以使用“use” 来使用某个数据库,如果要使用
    的数据库不存在,那么将会创建一个,会在真正向该库加入文档后,保存成为文件。
  • 删除数据库,命令:db.dropDatabase()
  • 显示现有的集合,命令:show collections 或者 tables;
  • 创建集合:
    在MongoDB中不用创建集合,因为没有固定的结构,直接使用db.集合名称.命令 来操作就可
    以了。如果非要显示创建集合的话,用:db.createCollecion(“集合名称”);
  • 插入并保存文档
    insert方法,可以单独插入一个文档,也可以插入多个,用“[ ]”即可。注意:
    1:MongoDB会为每个没有“_id”字段的文档自动添加一个”_id”字段
    2:每个Doc必须小于16MB
    3:可以在shell中执行Object.bsonsize(文档名称);来查看size大小
  • 删除文档:命令:remove , 可以按条件来删除
    只是删除文档,集合还在,如果使用 drop命令,会连带集合和索引都删掉
  • 查看集合中所有的文档,命令:db.集合名称.find();
  • 查看集合中第一个文档,命令:db.集合名称.findOne({条件对象});
  • 文档替换,命令: db.集合名称. update(条件,新的文档);
  • 更新修改器,用来做复杂的更新操作
    1:$set :指定一个字段的值,如果字段不存在,会创建一个
    2:$unset :删掉某个字段
    3:$inc :用来增加已有键的值,如果字段不存在,会创建一个。只能用于整型、长整型、或双精度浮点型的值。
    4:$push:向已有数组的末尾加入一个元素,要是没有就新建一个数组
    5:$each:通过一次$push来操作多个值
    6:$slice:限制数组只包含最后加入的n个元素,其值必须是负整数
    7:$sort:对数组中的元素,按照指定的字段来对数据进行排序(1为升序,-1为降序),然后再按照slice删除。注意:不能只将$slice或者$sort$push配合使用,且必须使用$each
    8:$ne:判断一个值是否在数组中,如果不在则添加进去
    9:$addToSet:将数组作为数据集使用,以保证数组内的元素不会重复
    10:$pop :从数组一端删除元素,{$pop:{key:1}},从末尾删掉一个,-1则从头部删除
  • save方法
    如果文档存在就更新,不存在就新建,主要根据”_id”来判断。
  • upsert
    找到了符合条件的文档就更新,否则会以这个条件和更新文档来创建一个新文档。
    指定update方法的第三个参数为true,可表示是upsert
  • 更新多个文档
    MongoDB默认只更新符合条件的第一个文档,要更新所有匹配的文档,把第4个参数
    设置为true。注意:
    1:只能用在$XXX的操作中
    2:最好每次都显示的指定update的第4个参数,以防止服务器使用默认行为
  • 查询更新了多少个文档
    使用命令:getLastError ,返回最后一次操作的相关信息,里面的n就是更新的文
    档的数量。形如:db.runCommand({“getLastError”:1});

MongoDB查询操作

  • 指定需要返回的键
    在find方法的第二个参数进行指定。默认情况下,始终会返回”_id”,可以通过设
    置字段为0来表示不返回这个字段。
  • 按条件查询
    在find方法里面加入条件数据即可,find方法的第一个参数就是。
    注意:条件数据必须是常量值,不能是另外的字段的数据
    1:比较操作:$lt,$lte,$gt,$gte,$ne
    2:$and:包含多个条件,他们之间为and的关系
    3:$or :包含多个条件,他们之间为or的关系 ,$nor相当于or取反
    4:$not:用作其他条件之上,取反
    5:$mod:将查询的值除以第一个给定的值,如果余数等于等二个值则匹配成功
    6:$in :查询一个键的多个值,只要键匹配其中一个即可 , $nin为不包含
    7:$all:键需要匹配所有的值
    8:$exists:检查某个键是否存在,1表示存在,0表示不存在
  • 正则表达式
    MongoDB使用Perl兼容的正则表达式(PCRE),比如:db.users.find({“name”:/sishuok/i}); 又比如:db.users.find({“name”:/^sishuok/});
  • 查询数组
    1:单个元素匹配,就跟前面写条件一样,{key:value}
    2:多个元素匹配,使用 all,key$all:[a,b]3使key.value4使 size
    5:指定子集,使用$slice,正数是前面多少条,负数是尾部多少条,也可以指定偏移量和要返回的元素数量,比如:$slice:[50,10]
    6:可以使用$来指定符合条件的任意一个数组元素,如:{”users.$”:1}
    7:$elemMatch:要求同时使用多个条件语句来对一个数组元素进行比较判断
  • 查询内嵌文档
    1:查询整个内嵌文档与普通查询是一样的
    2:如果要指定键值匹配,可以使用“.” 操作符,比如:{“name.first”:”a” ,“name.last”:”b”}
    3:如果要正确的指定一组条件,那就需要使用$elemMatch,以实现对内嵌文档的多个键进行匹配操

    注意:内嵌文档的查询必须要整个文档完全匹配
  • $where查询
    在查询中执行任意的JavaScript,通过编程来解决查询的匹配问题,方法返回boolean值。
function t1(){
    for(var a in this){
        if(a=="a"){return true;}
    } 
    return false;
}

使用的时候:db.users.find({“where”:t1});  
注意:
where性能较差,安全性也是问题,所以不到万不得已,不要使用
- 查询记录条数的命令:count
1:直接使用count()的话,得到的是整个记录的条数
2:如果要获取按条件查询后记录的条数,需要指定count(true或者非0的数)
● 限制返回的记录条数的命令:limit(要返回的条数)
● 限制返回的记录条数起点的命令:skip(从第几条开始返回)
● 排序的命令:sort({要排序的字段:1为升序,-1为降序})
1:可以对多个字段进行排序
2:MongoDB处理不同类型的数据是有一定顺序的,有时候一个键有多种类型的值,其排序顺序是预先定义好
的,从小到大如下:
(1)最小值 (2)null (3)数字 (4)字符串
(5)对象/文档 (6)数组 (7)二进制数据 (8)对象id
(9)布尔类型 (10)日期型 (11)时间戳 (12)正则表达式
(13)最大值
- 分页查询:组合使用limit,skipt和sort
当然也可以使用其他方式来分页,比如采用自定义的id,然后根据id来分页
- 查询给定键的所有不重复的数据,命令:distinct
- 游标
1:获取游标,示例如下:
var c = db.users.find();
2:循环游标,可以用集合的方式,示例如下:

while(c.hasNext()){
     printjson(c.next());
}

3:也可以使用forEach来循环,示例如下:

c.forEach(function(obj){
     print(obj);
});
  • 存储过程
    1:MongoDB的存储过程其实就是个自定义的js函数
    2:使用db.system.js.save({“_id”:名称,value:函数});
    3:可以通过如下命令查看:db.system.js.find();
    4:可以通过如下命令调用:db.eval(名称);

聚合框架

  • 简介
    MongoDB的聚合框架,主要用来对集合中的文档进行变换和组合,从而对数据进行分析以
    加以利用。
    聚合框架的基本思路是:采用多个构件来创建一个管道,用于对一连串的文档进行处理。
    这些构件包括:筛选(filtering)、投影(projecting)、分组(grouping)、排序(sorting)、限制
    (limiting)和跳过(skipping)。
  • 使用聚合框架的方式
    db.集合.aggregate(构件1,构件2…)
    注意:由于聚合的结果要返回到客户端,因此聚合结果必须限制在16M以内,这是MongoDB支持的
    最大响应消息的大小。
  • 准备样例数据
for(var i=0;i<100;i++){
    for(var j=0;j<4;j++){
db.scores.insert({"studentId":"s"+i,"course":"课程"+j,"score":Math.random()*100});
    }
}
  • 示例要完成的功能
    找出考80分以上的课程门数最多的3个学生,是用聚合框架来完成功能的步骤:
    1:找到所有考了80分以上的学生,不区分课程
    {“$match“:{“score”:{$gte:80}}}
    2:将每个学生的名字投影出来
    {“$project“:{“studentId”:1}}
    3:对学生的名字排序,某个学生的名字出现一次,就给他加1
    {“$group“:{“_id”:”$studentId“,”count”:{“$sum“:1}}}
    4:对结果集按照count进行降序排列
    {“$sort“:{“count”:-1}}
    5:返回前面的3条数据
    {“$limit“:3}
    最终执行的语句就是:
    db.scores.aggregate(
    {“$match“:{“score”:{$gte:80}}}
    , {“$project“:{“studentId”:1}}
    , {“$group“:{“_id”:”$studentId“,”count”:{“$sum“:1}}}
    , {“$sort“:{“count”:-1}}
    , {“$limit“:3}
    )
  • 管道操作符简介
    每个操作符接受一系列的文档,对这些文档做相应的处理,然后把转换后
    的文档作为结果传递给下一个操作符。最后一个操作符会将结果返回。
    不同的管道操作符,可以按照任意顺序,任意个数组合在一起使用。
    ● 管道操作符$match
    用于对文档集合进行筛选,里面可以使用所有常规的查询操作符。通常会
    放置在管道最前面的位置,理由如下:
    1:快速将不需要的文档过滤,减少后续操作的数据量
    2:在投影和分组之前做筛选,查询可以使用索引
  • 管道操作符$project
    用来从文档中提取字段,可以指定包含和排除字段,也可以重命名字段。
    比如要将studentId改为sid,如下:
    db.scores.aggregate({“$project“:{“sid”:”$studentId“}})
  • 管道操作符$project的数学表达式
    比如给成绩集体加20分,如下:
    db.scores.aggregate({“$project“:{“newScore”:{$add:[“$score“,20]}}})
    支持的操作符和相应语法:
    1:$add : [expr1[,expr2,…exprn]]
    2:$subtract:[expr1,expr2]
    3:$multiply:[expr1[,expr2,…exprn]]
    4:$divice:[expr1,expr2]
    5:$mod:[expr1,expr2]
  • 管道操作符$project的日期表达式
    聚合框架包含了一些用于提取日期信息的表达式,如下:
    $year$month$week$dayOfMonth$dayOfWeek$dayOfYear$hour$minute
    $second
    注意:这些只能操作日期型的字段,不能操作数据,使用示例:
    {“$project“:{“opeDay”:{“$dayOfMonth“:”$recoredTime“}}}
  • 管道操作符$project的字符串表达式
    1:$substr : [expr,开始位置,要取的字节个数]
    2:$concat:[expr1[,expr2,…exprn]]
    3:$toLower:expr
    4:$toUpper:expo,例如:{“$project“:{“sid”:{$concat:[“$studentId“,”cc”]}}}
  • 管道操作符$project的逻辑表达式
    1:$cmp:[expr1,expr2] :比较两个表达式,0表示相等,正数前面的大,负数后面的大
    2:$strcasecmp:[string1,string2] :比较两个字符串,区分大小写,只对由罗马字符组成的字符串有效
    3:$eq$ne$gt$gte$lt$lte:[expr1,expr2]
    4:$and$or$not
    5:$cond:[booleanExpr,trueExpr,falseExpr]:如果boolean表达式为true,返回true表达式,否则返回false表达式
    6:$ifNull:[expr,otherExpr]:如果expr为null,返回otherExpr,否则返回expr
    例如:db.scores.aggregate({“$project“:{“newScore”:{$cmp:[“$studentId“,”sss”]}}})
  • $group
    用来将文档依据特定字段的不同值进行分组。选定了分组字段过后,就可以把这些字段传递给$group函数的“_id”字段了。例如:
    db.scores.aggregate({“$group”:{“_id”:“$studentId”}}); 或者是
    db.scores.aggregate({“$group“:{“_id”:{“sid”:”$studentId“,”score”:”$score“}}});
  • $group支持的操作符
    1:$sum:value :对于每个文档,将value与计算结果相加
    2:$avg:value :返回每个分组的平均值
    3:$max:expr :返回分组内的最大值
    4:$min:expr :返回分组内的最小值
    5:$first:expr :返回分组的第一个值,忽略其他的值,一般只有排序后,明确知道数据顺序的时候,这个操作才有意义
    6:$last:expr :与上面一个相反,返回分组的最后一个值
    7:$addToSet:expr :如果当前数组中不包含expr,那就将它加入到数组中
    8:$push:expr:把expr加入到数组中
  • 拆分命令:$unwind
    用来把数组中的每个值拆分成为单独的文档。
  • 排序命令:$sort
    可以根据任何字段进行排序,与普通查询中的语法相同。如果要对大量的文档进行
    排序,强烈建议在管道的第一个阶段进行排序,这时可以使用索引。
  • 常见聚合函数
    1:count:用于返回集合中文档的数量
    2:distinct:找出给定键的所有不同值,使用时必须指定集合和键,例如:
    db.runCommand({“distinct”:”users”,”key”:”userId”});
  • MapReduce介绍
    在MongoDB的聚合框架中,还可以使用MapReduce,它非常强大和灵活,但具有一定
    的复杂性,专门用于实现一些复杂的聚合功能。
    MongoDB中的MapReduce使用JavaScript来作为查询语言,因此能表达任意的逻辑,
    但是它运行非常慢,不应该用在实时的数据分析中。
  • MapReduce的HelloWorld实现的功能,找出集合中所有的键,并统计每个键出现的次数。
    1:Map函数使用emit函数来返回要处理的值,示例如下:
var map = function(){
for(var key in this){
     emit(key,{count:1});
     }
}

this表示对当前文档的引用。
2:reduce函数需要处理Map阶段或者是前一个reduce的数据,因此reduce返回的文档必须要能
作为reduce的第二个参数的一个元素,示例如下:

var reduce = function(key,emits){
var total = 0;
for(var i in emits){
     total += emits[i].count;
}
return {"count":total};
};

3:运行MapReduce,示例如下:

var mr = db.runCommand({"mapreduce":"users","map":map,"reduce":reduce,"out":"mrout"});

4:查询最终的结果,示例如下:
db.mrout.find();
- 还可以改变一下,比如统计userId中值,以及每个值出现的次数,就可以如下操作
1:修改map函数,示例如下:

var map = function(){
     emit(this.userId,{count:1});
};

2:reduce函数不用改
3:重新执行

db.runCommand({"mapreduce":"users","map":map,"reduce":reduce,"out":"mrout"});

4:查看最终结果:

db.mrout.find();
  • 更多MapReduce可选的键
    1:finalize:function :可以将reduce的结果发送到finalize,这是整个处理的最后一步
    2:keeptemp:boolean :是否在连接关闭的时候,保存临时结果集合
    3:query:document :在发送给map前对文档进行过滤
    4:sort:document :在发送给map前对文档进行排序
    5:limit:integer :发往map函数的文档数量上限
    6:scope:document :可以在javascript中使用的变量
    7:verbose:boolean :是否记录详细的服务器日志
    示例:
var query = {"userId":{"$gt":"u2"}}
var sort = {"userId":1};
var finalize = function(key,value){
r     eturn {"mykey":key,"myV":value};
};
var mr =
db.runCommand({"mapreduce":"users","map":map,"reduce":reduce,"out":"mrout","que
ry":query,"sort":sort,"limit":2,"finalize":finalize});
  • 聚合命令group
    用来对集合进行分组,分组过后,再对每一个分组内的文档进行聚合。
    比如要对studentId进行分组,找到每个学生最高的分数,可以如下步骤进行:
    1:测试数据就用聚合框架一开始准备的数据
    2:使用group,示例如下:
db.runCommand({"group":{
    "ns":"scores",
    "key":{"studentId":1},
    "initial":{"score":0},
    "$reduce":function(doc,prev){
        if(doc.score > prev.score){
             prev.score = doc.score;
        }
    }
}});

ns:指定要分组的集合
key:指定分组的键
initial:每一组的reduce函数调用的时候,在开头的时候调用一次,以做初始化
$reduce:在每组中的每个文档上执行,系统会自动传入两个参数,doc是当前处理的文档,prev是本组前一次执行的结果文档
3:你还可以在group的时候添加条件,就是加入condition,示例如:
“condition”:{“studentId”:{“$lt“:”s2”}}
4:同样可以使用finalizer来对reduce的结果进行最后的处理,比如要求每个学生的平均分,
就可以先按照studentId分组,求出一个总的分数来,然后在finalizer里面,求平均分:

db.runCommand({"group":{
"ns":"scores",
"key":{"studentId":1},
"initial":{"total":0},
"$reduce":function(doc,prev){
     prev.total += doc.score;
},
"condition":{"studentId":{"$lt":"s2"}},
"finalize":function(prev){
     prev.avg = prev.total/3;
}
}});

注意:finalize是只在每组结果返回给用户前调用一次,也就是每组结果只调用一次
5:对于分组的key较为复杂的时候,还可以采用函数来做为键,比如让键不区分大小下,就可以如下定义:

db.runCommand({"group":{
"ns":"scores",
$keyf:function(doc){
return {studentId:doc.studentId.toLowerCase()};
},
"initial":{"total":0},
"$reduce":function(doc,prev){
prev.total += doc.score;
},
"condition":{"$or":[{"studentId":{"$lt":"s2"}},{"studentId":"S0"}]},
"finalize":function(prev){
prev.avg = prev.total/3;
}
}});

注意:要使用$keyf来定义函数作为键,另外一定要返回对象的格式

理解MongoDB的文档存储

  • 将文档插入到MongoDB的时候,文档是按照插入的顺序,依次在磁盘上相邻保存,因此,一个文档变大了,原来的位置要是放不下这个文档了,就需要把这个文档移动到集合的另外一个位置,通常是最后,能放下这个文档的地方。
  • MongoDB移动文档的时候,会自动修改集合的填充因子(padding
    factor),填充因子是为新文档预留的增长空间,不能手动设定填充因子。
    1:填充因子开始可能是1,也就是为每个文档分配精确的空间,不预留增长空间
    2:当有文档超长而被迫移动文档的时候,填充因子会增大
    3:当集合中不再有文档移动的时候,填充因子会慢慢减小
  • MongoDB进行文档移动是非常慢的移动文档的时候,MongoDB需要将文档原先占用的空间释放掉,然后将文档写入新的空间,相对费时,尤其是文档比较大,又频繁需要移动的话,会严重影响性能

MongoDB的索引

  • 创建索引,命令:ensureIndex
    1:创建索引时,1表示按升序存储,-1表示按降序存储
    2:可以给索引指定名字,创建的时候指定 name 即可
    3:可以创建复合索引,如果想用到复合索引,必须在查询条件中包含复合索引中的前N个索引列
    4:如果查询条件中的键值顺序和复合索引中的创建顺序不一致的话,MongoDB可以智能的帮助我们调
    整该顺序,以便使复合索引可以为查询所用
    5:可以为内嵌文档创建索引,其规则和普通文档创建索引是一样的
    6:一次查询中只能使用一个索引,$or特殊,可以在每个分支条件上使用一个索引
    7:如果查询要在内存中排序的话,结果集不能超过32M
    8:$where,$exists不能使用索引,还有一些低效率的操作符,比如:$ne,$not,$nin
    9:设计多个字段的索引时,应该尽量将用于精确匹配的字段放在索引的前面
    10:MongoDB限制每个集合上最多只能有64个索引,建议在一个特定的集合上,不要设置多个索引。
    11:如果要在后台运行创建索引,添加 {background:true}
  • 查看已经创建的索引,命令:getIndexes
  • 删除索引,命令:dropIndex
  • 查看查询语句解释,命令:explain
  • explain的字段说明:
    1:cursor:本次查询使用的索引
    2:isMultiKey:是否使用了多键索引
    3:n:返回的文档数量
    4:nscannedObjects:按照索引指针去磁盘查找实际文档的次数
    5:nscanned:如果使用索引,就是查找过的索引条目数量;如果全表扫描,就是查
    找过的文档数量
    6:scanAndOrder:是否在内存中对结果集排序
    7:indexOnly:是否只是用索引就能完成本次查询
    8:nYields:为了让写入请求能顺利执行,本次查询暂停的次数
    9:millis:本次查询所耗费的时间,单位是毫秒
    10:indexBounds:描述索引的使用情况,给出了索引的遍历范围
  • 指定使用的索引:hint
  • 指定不使用索引,强制全表扫描:查询.hint({$natural:1});
  • 唯一索引:在创建的时候,指定{“unique”:true}
    1:唯一索引将会保证该字段的数据不会重复,如果重复插入,只会保存一条
    2:索引能保存的数据值必须小于1024字节,这意味着超长的数据,不会保存到索引里,因此也就可以插入多个重复的数据了
    3:复合索引也可以创建为唯一索引
    4:在已有集合上创建唯一索引可能会失败,因为已经有了重复数据,此时可以指定dropDups来强制去重,但由于保留数据的不可控,因此对重要数据不建议使用
    5:唯一索引会把null看作值,所以无法将多个缺少唯一索引的数据插入,这时可以指定sparse来创建一个稀疏索引,如:{“unique”:true,”sparse”:true}
  • 索引的集合
    所有索引信息都保存在system.indexes集合众,这是一个保留集合
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值