MongoDB 4.0.10 聚合
- db.<collection>.group(document):首先根据cond查询条件筛选符合条件的数据,然后按照key分组属性把数据分成不同组,每一组都经过initial进行变量初始化,在经过reduce函数进行计算,其中curr参数代表该组的一个文档,result参数在最后的时候返回,统计完该组之后调用finalize函数
- group方法的不足之处:需要手写聚合函数的业务逻辑,且不支持分片计算,无法分布式计算
- 示例在SQL_DB中Learn09.js
1 db.<collection>.group(document) 2 // document指定是 3 { 4 key:{key1:1, key2:1}, // 分组属性 5 keyf:{ }, // 可选,用于代替参数key,可以不指定其属性为分组字段的对象,而是指定一个函数,该函数返回一个用于分组的key对象 6 cond:{ }, // 可选,查询条件 7 reduce:function(curr, result){ }, // 每一组数据执行的聚合函数,curr代表该组的一个文档,result代表该组的一个聚合结果 8 initial:{}, // 进入每组之前进行变量参数初始化 9 finalize:function(){ } // 可选,统计完一组后的回调函数 10 }
- db.<collection>.aggregate(AGGREGATE_OPERATION),V2.2加入:这是MongoDB的聚合管道,将MongoDB文档在一个管道处理完毕之后将结果传递给下一个管道处理,管道操作是可以重复的
- 示例在SQL_DB中Learn10.js
1 $project //select 修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档 2 $match //where/having 用于过滤数据,只输出符合条件的文档;$match使用MongoDB的标准查询操作 3 $limit //limit 用来限制MongoDB聚合管道返回的文档数 4 $skip // 在聚合管道中跳过指定数量的文档,并返回余下的文档 5 $unwind // 将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值 6 $group //group by 将集合中的文档分组,可用于统计结果 7 $sort //order by 将输入文档排序后输出 8 $geoNear // 输出接近某一地理位置的有序文档 9 10 db.<collection>.aggregate(AGGREGATE_OPERATION) 11 //示例 12 // SELECT column_name,COUNT(column_name) AS total FROM kr GROUP BY column_name 13 db.kr.aggregate([ 14 {$group:{_id:"$column_name",total:{$sum:1}}} 15 ]) 16 // 按照column_name和article_id进行聚合 17 db.kr.aggregate([ 18 {$group : {_id : {key1:"$column_name", key2:"$article_id"}, num_total : {$sum : 1}}} 19 ]) 20 db.runoob.aggregate([{$project:{title:1,url:1,_id:0}}]) // 显示title、url字段 21 db.runoob.aggregate([{$match:{likes:{$gt:100,$lte:1500}}}]) // 筛选100<likes<=1500的文档 22 db.runoob.aggregate([{$skip:10}]) // 跳过前10个文档 23 db.runoob.aggregate([{$limit:3}]) // 显示前三个文档 24 db.runoob.aggregate([{$unwind:"$tags"}]) // tags字段是数组类型,将其进行拆分 25 db.runoob.aggregate([{$sort:{likes:1}}]) // 按likes字段升序排列,1代表升序,-1代表降序
- aggregate()方法中$group中的修饰符
1 $sum // sum()/count() 对设置的属性按分组计算总和,如果不是数值类型,则结果为0,设置为1,则为count(*)计数统计 2 $avg // 对设置的属性按分组计算平均值,如果不是数值类型,则返回null 3 $min // 获取集合中所有文档对应值得最小值, 分组取最小 4 $max // 获取集合中所有文档对应值得最大值, 分组取最大 5 $push // 在结果文档中插入值到一个数组中,将聚合之后的结果形成一个数组,如果按某个属性聚合之后,对A属性进行push,这把分组中所有的A属性放在一个数组里面 6 $addToSet // 在结果文档中插入值到一个数组中,但不创建副本 7 $first // 根据资源文档的排序获取每个分组第一个文档数据 8 $last // 根据资源文档的排序获取每个分组最后一个文档数据
- mapReduce(),V2.4加入
- 关系数据的group不支持分布式运算,而且在单台服务器的运算能力必然是有限的,而mapReduce支持分布式运算,可以在大量的服务器上同时工作,以空间换结果
- map函数首先按照分组的属性进行分组,将同属于一个组的数据映射到一个数组上去,reduce函数则是将分好的数组进行计算
- 大坑:分组数据如果大于100,那么它每次取完100条,归并为1条,又返回给map函数作为输入,判断是否余数是否大于100,大于100,取100条,周而复始,直到最后一次取数不大于100,运算完成后就结束
- 大坑:使用Group或MapReduce时,如果一个分类只有一个元素,那么Reduce函数将不会执行,但Finalize函数还是会执行的;这时要在Finalize函数中考虑一个元素与多个元素返回结果的一致性
- 示例在SQL_DB中Learn11.js、Learn12.js
1 db.<collecton>.mapReduce( 2 function(){ emit(key, value);}, // map函数,映射函数,key为统计的键,可以自定义;value为需要添加到数组的值的属性,可以多个 3 function(key, values){ return reduceFunction }, // reduce统计函数,key为统计的键;values为数组 4 { 5 out: <collection>, // 统计结果放在集合中,如果不指定out:{inline:1}则使用临时集合,在客户端断开后自动删除 6 query: <document>, // 筛选条件,只有符合条件的数据才会发到map函数 7 sort: <document>, // 排序后发给map函数 8 limit: <number>, // 发给map函数的数据数量 9 finalize: <function>, // 在reduce函数执行完后执行,将键和文档作为参数,返回修改的文档 10 scope: <document>, // 指定map、reduce、finalize的全局变量 11 jsMode: <boolean>, // 指定是否在执行map和reduce函数直接将中间数据转换为BSON格式,默认为false,将map发出的js对象转换为BSON对象,调用reduce将BSON对象转换为js对象 12 verbose: <boolean>, // 指定是否包含timing信息,默认为false,不包含 13 bypassDocumentValidation: <boolean> // 是否允许mapReduce在操作期间绕过文档验证,这使得可以插入不符合验证要求的文档 14 } 15 )
- aggregate():聚合表达式中使用的字符串运算符和算术运算符
1 $add // 计算数值的总和。例如:valuePlus5:{$add:["$value",5]} 2 $divide // 给定两个数值,用第一个数除以第二个数。例如:valueDividedBy5:{$divide:["$value",5]} 3 $mod // 取模。例如:{$mod:["$value",5]} 4 $multiply // 计算数值数组的乘积。例如:{$multiply:["$value",5]} 5 $subtract // 给定两个数值,用第一个数减去第二个数。例如:{$subtract:["$value",5]} 6 $concat // 连接两个字符串 例如:{$concat:["str1","str2"]} 7 $strcasecmp // 比较两个字符串并返回一个整数来反应比较结果。例如 {$strcasecmp:["$value","$value"]} 8 $substr // 返回字符串的一部分。例如:hasTest:{$substr:["$value","test"]} 9 $toLower // 将字符串转化为小写 10 $toUpper // 将字符串转化为大写
- aggregate():时间关键字
1 $dayOfYear // 返回该日期是这一年的第几天 (全年 366 天) 2 $dayOfMonth // 返回该日期是这一个月的第几天 (1到31) 3 $dayOfWeek // 返回的是这个周的星期几 (1:星期日,7:星期六) 4 $year // 返回该日期的年份部分 5 $month // 返回该日期的月份部分 (1到12) 6 $week // 返回该日期是所在年的第几个星期 (0到53) 7 $hour // 返回该日期的小时部分 8 $minute // 返回该日期的分钟部分 9 $second // 返回该日期的秒部分 (以0到59之间的数字形式返回日期的第二部分,但可以是60来计算闰秒) 10 $millisecond // 返回该日期的毫秒部分 (0到999) 11 $dateToString // { $dateToString: {format:"",date:""} } 12 // %Y Year (4 digits, zero padded) 0000-9999 13 // %m Month (2 digits, zero padded) 01-12 14 // %d Day of Month (2 digits, zero padded) 01-31 15 // %H Hour (2 digits, zero padded, 24-hour clock) 00-23 16 // %M Minute (2 digits, zero padded) 00-59 17 // %S Second (2 digits, zero padded) 00-60 18 // %L Millisecond (3 digits, zero padded) 000-999 19 // %j Day of year (3 digits, zero padded) 001-366 20 // %w Day of week (1-Sunday, 7-Saturday) 1-7 21 // %U Week of year (2 digits, zero padded) 00-53 22 // %% Percent Character as a Literal % 23 db.runoob.aggregate([{$project:{createDate:1,_id:0,dayOfYear:{$dayOfYear:"$createDate"},year:{$year:"$createDate"}}}]) 24 db.runoob.aggregate([{$project:{createDate:1,_id:0,newdate:{$dateToString:{format:"%Y",date:"$createDate"}}}}])
![](https://img2020.cnblogs.com/blog/1378165/202008/1378165-20200815235534725-270575357.png)