mongodb聚合管道中常见聚合函数的参考与演示——按类型分组区分
>说明数据准备数值相关聚合函数abs—求绝对值add—数字或日期相加avg—求平均值ceil—向上取整floor—向下取整divide—两数相除exp—提高欧拉数(即e) 到指定的 index ln—Log n计算对数log—log n 计算指定基数的对数log10—计算基数为10的对数max—获取最大值min—获取最小值mod—两个数取余multiply—两数相乘pow—幂运算rand—获取随机数,返回0-1之前的浮点数round—四舍五入sqrt—计算正数的平方根subtract—两数相减返回差值sum—获取总数trunc—截取小数点,保留几位小数,默认不保留字符串相关聚合函数binarySize—查看字符串或二进制数据的内容大小(以字节为单位)bsonSize—查看文档大小concat—链接字符串并返回结果indexOfBytes—查询字符串中指定字符串的索引位置indexOfCP—查询字符串中指定字符串的索引位置ltrim—去除左边的指定字符串、默认空格rtrim—去除右边的指定字符串、默认空格regexFind—正则查找regexFindAll—正则查找符合条件的所有项regexMatch—判断是否匹配replaceOne—替换第一次匹配的字符串replaceAll—替换所有匹配的字符串split—按照某字符切割字符串strcasecmp—对比字符串大小,不区分大小写strLenBytes—获取UTF8编码的字节数strLenCP—返回UTF-8的数量substr、substrBytes—截取字符串substrCP—截取字符串trim—去除左右两边的指定字符串、默认空格数组相关聚合函数addToSet—返回唯一值数组arrayElemAt—获取数组的指定下标值arrayToObject—将数组转换成对象concatArrays—链接数组并返回结果filter—过滤数组first—获取第一个元素,常用于数组in—判断数组是否包含某个元素indexOfArray—查询数组中指定元素last—取最后一个文档last(Array)—取数组中最后一个元素map—遍历操作每个元素,并返回修改后的结果objectToArray—对象转成数组push—往数组中添加元素range—获取一批有序数组reduce—遍历数组组成一个值reverseArray—将数组前后颠倒setDifference—比较两个数组,寻找相较于第一个数组的差集setEquals—比较多个数组是否含有相同元素setField—添加、修改、移除字段setIntersection—比较多个数组,并将交集结果返回setIsSubset—比较两个数组判断子集setUnion—比较多个数组,并将并集结果返回size—获取数组大小slice—切割数组zip—转置数组判断相关操作and—bool运算且allElementsTrue—判断所有元素是否全为TrueanyElementTrue—判断所有元素是否有一个为Trueor—bool或运算cmp—比较两个数并返回cond—条件判断,if elseeq—判断两值相等isArray—判断是否为数组类型isNumber—判断是否为数值类型ifNull—先判断空值再取值gt、gte—判断数值大于、大于等于某个值lt、lte—判断数值小于、小于等于某个值ne—比较两数不相等not—非、不switch—switch case条件语句类型相关聚合函数convert—转换类型toBool—转布尔类型toDate—转时间类型toDecimal—转换Decimal数值类型toDouble—转换成Double类型toInt—转换成Integer类型toLong—转换成Long类型toObjectId—转换成ObjectId类型toString—转换成String类型toLower—将字符串转为小写字母toUpper—将字符串转为大写字母type—查看类型时间相关操作dateAdd—添加时间dateDiff—比较两个时间的差dateFromParts—根据指定时间参数转换为时间类型dateFromString—从字符串转换成事件类型dateSubtract—递减时间dateToParts—将时间解析成各个时间组成部分dateToString—日期转字符串dateTrunc—截断日期dayOfMonth—查询一月之中的第几天、0-31dayOfWeek—查询一周之中的第几天,1-7dayOfYear—查询一年之中的第几天,0-365hour—获取时间中的小时值isoDayOfWeek—ISO 查询一周之中的第几天,1-7isoWeek—ISO 查询一年之中的第几周,1-53isoWeekYear—ISO 查询年份millisecond—获取某个时间的毫秒值,0-999minute—获取某个时间的分钟值,0-59month—获取某个时间的月份值,1-12second—获取某个时间的秒值,0-59week—获取某个时间的周值,0-53year—获取某个时间的年份值,0-9999文档相关count—获取文档总数documentNumber—返回文档在 $setWindowFields 阶段分区中的位置(称为文档编号)getField—获取某个字段的值let—声明变量操作变量literal—返回一个不进行解析的值mergeObjects—将多个文档合并为一个文档meta—查看文档与索引的匹配分数sampleRate—按照几率随机采样文档unsetField—删除查询文档结果中的字段
说明
仅为个人整理及理解,大多数都是参照官方文档,记录只是为了加深印象而已,有些数学函数未作测试,有些做了测试也还是没能理解这个函数有什么用...
未做测试的函数(大多为数学三角函数、方差函数):accumulator、acos、acosh、asin、asinh、atan、atan2、atanh、cos、cosh、covariancePop 、covarianceSamp、degreesToRadians、degreesRank、derivative、expMovingAvg、function、sin、sinh、stdDevSamp、tan、tanh
参考:Aggregation Pipeline Operators — MongoDB Manual
点击查看按照顺序整理的
数据准备
xxxxxxxxxxuse testdata = [ { _id: 1, name: 'tom', sex: '男', score:{yw:100,sx:50}, age: 34,update_at:1533657600000,create_at:1520481600000,favorites: [ "chocolate", "cake"]}, { _id: 2, name: 'jeke', sex: '男', score:{yw:90,sx:60}, age: 24,update_at:1533657600000,create_at:1520478000000,favorites: [ "chocolate", "apples" ]}, { _id: 3, name: 'kite', sex: '女', score:{yw:40,sx:70}, age: 36,update_at:1533657600000,create_at:1520514000000,favorites: [ "chocolate","butter", "apples" ]}, { _id: 4, name: 'herry', sex: '男', score:{yw:90,sx:77}, age: 56,update_at:1533657600000,create_at:1520366400000,favorites: [ "cake", "butter"]}, { _id: 5, name: 'marry', sex: '女', score:{yw:70,sx:55}, age: 18,update_at:1533657600000,create_at:1520474400000,favorites: ["cake","apples" ]}, { _id: 6, name: 'john', sex: '男', score:{yw:100,sx:93}, age: 31 ,update_at:1533657600000,create_at:1520391600000,favorites: [ "butter"]}]db.students.insertMany(data)data = [ { _id: 1, province: 'GuangGong', country: 'China', detail: '幸福小区001弄',student_id:6}, { _id: 2, province: 'Tokyo', country: 'Japan', detail: '幸福小区002弄',student_id:6}, { _id: 3, province: 'ShangHai', country: 'China', detail: '幸福小区003弄',student_id:5}, { _id: 4, province: 'BeiJing', country: 'China', detail: '幸福小区004弄',student_id:4}, { _id: 5, province: 'MingGuWu', country: 'Japan', detail: '幸福小区005弄',student_id:3}, { _id: 6, province: 'XiNi', country: 'Australia', detail: '幸福小区006弄',student_id:2}, { _id: 7, province: 'NewYork', country: 'America', detail: '幸福小区006弄',student_id:1},]db.address.insertMany(data)# 查看数据db.students.find().limit(1)db.address.find().limit(1)注意时间戳这里存的是以毫秒为单位的,让我们查看其中一条数据

数值相关聚合函数
abs—求绝对值
如求学生的数学成绩与60之间的绝对值
xxxxxxxxxxdb.students.aggregate([{ $project: { abs_age: { $abs: { $subtract:['$score.sx',60] } } }}])
add—数字或日期相加
求学生的数学成绩与语文成绩总和,并将创建时间添加一天
添加时间时默认单位时毫秒,一天间隔 86400000 毫秒
xxxxxxxxxxdb.students.aggregate([{ $project: { abs_age: { $add:['$score.sx','$score.yw'] }, create_at:1, create_at_now:{ $add:['$create_at',86400000] } }}])
avg—求平均值
仅支持在$addFields、$bucket、$bucketAuto、$group、$match、$project、$replaceRoot、$replaceWith、$set、$setWindowField这几个管道中使用
查看学生平均成绩
xxxxxxxxxxdb.students.aggregate([{ $project: { age_avg:{ $avg:['$score.sx','$score.yw'] } }}])
ceil—向上取整
xxxxxxxxxxdb.students.aggregate([{ $project: { age_divide:{$divide:['$age',10]}, age_ceil:{ $ceil:{ $divide:['$age',10] } } },}])
floor—向下取整
与ceil向上取整相对应
xxxxxxxxxxdb.students.aggregate([{ $group:{ _id:'$sex', avg_age:{$avg:'$age'} }},{ $project:{ age_avg:'$avg_age', age_ceil:{$ceil:'$avg_age'}, age_floor:{$floor:'$avg_age'}, }}])
divide—两数相除
前者除以后者,如学生的年龄除以10
xxxxxxxxxxdb.students.aggregate([{ $project:{ age:1, age_10:{ $divide:['$age',10] }, }}])
exp—提高欧拉数(即e) 到指定的 index
不知道有什么用
xxxxxxxxxxdb.students.aggregate([{ $project:{ exp0:{ $exp:0 }, exp2:{ $exp:2 }, exp10:{ $exp:10 }, }},{$limit:1}])
ln—Log n计算对数
xxxxxxxxxxdb.students.aggregate([{ $project:{ age:1, age_ln:{ $ln:'$age' }, ln_1:{ $ln:1 }, ln_e:{ $ln:Math.E }, ln_10:{ $ln:10 }, ln_null:{ $ln:null } }},{$limit:1}])
log—log n 计算指定基数的对数
{$log:[数值,基数]}—基数要大于1
xxxxxxxxxxdb.students.aggregate([{ $project:{ age:1, age_log:{ $log:['$age',10] }, log_1:{ $log:[1,2] }, log_100:{ $log:[100,10] } }},{$limit:1}])
log10—计算基数为10的对数
xxxxxxxxxxdb.students.aggregate([{ $project:{ age:1, age_log10:{ $log10:'$age' }, log10_1:{ $log10:1 }, log10_100:{ $log10:100 } }},{$limit:1}])
max—获取最大值
xxxxxxxxxxdb.students.aggregate([{ $group:{ _id:'$sex', max_age:{ $max:'$age' } }},{ $project:{ max_age:1, max_arr:{ $max:[0,5,7,6,14,2,3] } }}])
min—获取最小值
xxxxxxxxxxdb.students.aggregate([{ $group:{ _id:'$sex', min_age:{ $min:'$age' } }},{ $project:{ min_age:1, min_arr:{ $min:[0,5,7,6,14,2,3] } }}])
mod—两个数取余
注意:不能对0取余
xxxxxxxxxxdb.students.aggregate([{ $project:{ age:1, mod_age:{ $mod:['$age','$age'] }, mod_age_10:{ $mod:['$age',10] }, mod_0:{ $mod:[0,'$age'] }, mod_1:{ $mod:[1,'$age'] }, }},{$limit:1}])
multiply—两数相乘
xxxxxxxxxxdb.students.aggregate([{ $project:{ age:1, age_10:{ $multiply:['$age',10] }, age2:{ $multiply:['$age',2] } }},{$limit:1}])
pow—幂运算
xxxxxxxxxxdb.students.aggregate([{ $project:{ pow_0:{ $pow:[5,0] }, pow_2:{ $pow:[5,2] }, 'pow_-2':{ $pow:[5,-2] } }},{$limit:1}])
rand—获取随机数,返回0-1之前的浮点数
xxxxxxxxxxdb.students.aggregate([{ $project:{ rand:{ $rand:{} }, rand_0_5:{ $ceil:{ $multiply:[{$rand:{}},5] } } }},{$limit:1}])
round—四舍五入
基础语法
xxxxxxxxxx{ $round : [ <number> 数据源, <place> 保留几位小数点、-20至100之间、可选默认0 ] }xxxxxxxxxxdb.students.aggregate([{ $project:{ round:{ $round:[1.568475] }, round_2:{ $round:[1.568475,2] }, 'round_-2':{ $round:[1.568475,-2] } }},{$limit:1}])
sqrt—计算正数的平方根
xxxxxxxxxxdb.students.aggregate([{ $project:{ sqrt_result_25:{ $sqrt:25 }, sqrt_result_100:{ $sqrt:100 }, sqrt_result_88:{ $sqrt:88 }, }},{$limit:1}])
subtract—两数相减返回差值
如查看学生年龄离30岁还有多远
xxxxxxxxxxdb.students.aggregate([{ $project:{ age:1, age_substract:{ $subtract:['$age',30] } }}])
sum—获取总数
仅支持addFields、bucket、bucketAuto、group、match、project、replaceRoot、replaceWith、set、setWindowFields阶段中使用
如按照学生性别分组,分别计算出数学、语文的总成绩
xxxxxxxxxxdb.students.aggregate([{ $group:{ _id:'$sex', sx:{ $sum:'$score.sx' }, yw:{ $sum:'$score.yw' } }}])
trunc—截取小数点,保留几位小数,默认不保留
xxxxxxxxxxdb.students.aggregate([{ $project:{ trunc:{ $trunc:[1.5555] }, trunc_2:{ $trunc:[3.33333,2] }, trunc_3:{ $trunc:[-6.666666,3] }, }},{$limit:1}])
字符串相关聚合函数
binarySize—查看字符串或二进制数据的内容大小(以字节为单位)
版本要求:v4.4+
官方例子
xxxxxxxxxxdb.students.aggregate([{ $project:{ bs_str:{ $binarySize:'abcdEFG' }, bs_str2:{ $binarySize:'Hello World!' }, bs_str3:{ $binarySize:'!!!!' }, bs_str4:{ $binarySize:'cafétéria' }, bs_str5:{ $binarySize:"€λG" }, bs_str6:{ $binarySize:'你好' }, bs_bytes:{ $binarySize:new BinData(0, "MyIRAFVEd2aImaq7zN3u/w==") }, }},{$limit:1}])空格占1字节、中文符号占1字节、é占2字节、€占3字节λ占2字节、汉字占3字节

bsonSize—查看文档大小
版本要求:v4.4+
$$ROOT表示当前文档根目录,即整个文档
xxxxxxxxxxdb.students.aggregate([{ $project:{ bs:{ $bsonSize:'$$ROOT' } }}])
concat—链接字符串并返回结果
仅支持字符串链接,若为其他类型请先转成字符串
xxxxxxxxxxdb.students.aggregate([{ $project: { score_cmp:{ $concat:[ '$name', '成绩——语文:', {$toString:'$score.yw'}, ',数学:' ,{$toString:'$score.sx'} ] } },}])
indexOfBytes—查询字符串中指定字符串的索引位置
查询字符串中第一次出现的UTF-8字符并返回索引,若不包含则返回-1
基础语法
xxxxxxxxxx{ $indexOfBytes: [ <string expression> 字符串, <substring expression> 指定字符串, <start> 开始查找的位置下标、默认0、可选, <end> 结束查找的位置下标、默认结尾、可选] }如查找学生名字带有a字符串的学生
xxxxxxxxxxdb.students.aggregate([{ $project:{ name:1, name_index:{ $indexOfBytes:['$name',"a"] }, name_index_start:{ $indexOfBytes:['$name',"a",2] }, name_index_end:{ $indexOfBytes:['$name',"a",0,2] } }}])# name_index_start 从第三个开始查找(不查找前三个)# name_index_end 从第1个开始查找,第三个停止查找(只查找前三个)
indexOfCP—查询字符串中指定字符串的索引位置
查询字符串中第一次出现的字符串并返回索引,若不包含则返回-1,不明白indexOfCP和indexOfBytes有什么区别
基础语法
xxxxxxxxxx{ $indexOfCP: [ <string expression> 字符串, <substring expression> 指定字符串, <start> 开始查找的位置下标、默认0、可选, <end> 结束查找的位置下标、默认结尾、可选] }如查找学生名字带有a字符串的学生
xxxxxxxxxxdb.students.aggregate([{ $project:{ name:1, name_index:{ $indexOfCP:['$name',"a"] }, name_index_start:{ $indexOfCP:['$name',"a",2] }, name_index_end:{ $indexOfCP:['$name',"a",0,2] } }}])# name_index_start 从第三个开始查找(不查找前三个)# name_index_end 从第1个开始查找,第三个停止查找(只查找前三个)
ltrim—去除左边的指定字符串、默认空格
基础语法,与rtrim相对应
xxxxxxxxxx{ $ltrim: { input: <string> 字符串, chars: <string> 去除的指定字符、默认空字符串、可选 } }xxxxxxxxxxdb.students.aggregate([{ $project:{ ltrim_str:{ $ltrim:{input:'Hello World'} }, ltrim_str_He:{ $ltrim:{input:'He llo World',chars:'He'} }, ltrim_str_space:{ $ltrim:{input:'\t \r\n Hello World'} }, }},{$limit:1}])
rtrim—去除右边的指定字符串、默认空格
基础语法,与ltrim去除左边相对应
xxxxxxxxxx{ $rtrim: { input: <string> 字符串, chars: <string> 去除的指定字符、默认空字符串、可选 } }xxxxxxxxxxdb.students.aggregate([{ $project:{ rtrim_str:{ $rtrim:{input:'Hello World'} }, rtrim_str_He:{ $rtrim:{input:'Hello World',chars:'ld'} }, rtrim_str_space:{ $rtrim:{input:'Hello World\t \r\n '} }, }},{$limit:1}])
regexFind—正则查找
版本要求:4.2+
基础语法
xxxxxxxxxx{ $regexFind: { input: <expression> 数据源, regex: <expression> 正则表达式, options: <expression> 选项、可选、i忽略大小写、m锚点或换行符优化、x忽略空白字符、s允许.匹配所有包括空白字符 }}# m配置说明:添加m配置换行后也有可能命中开始或结束锚点,若数据源没有换行符或者正则表达式中没有锚点,那么此时指定m是无意义的# 匹配成功返回# { "match" : <string>, "idx" : <num>, "captures" : <array of strings> }# 否则返回Nulli、m选项匹配
xxxxxxxxxxdb.students.aggregate([{ $project:{ regex_result:{ $regexFind:{ input:'Hello World!!!', regex:/he/ } }, regex_result_i:{ $regexFind:{ input:'Hello World!!!',regex:/he/,options:'i' } }, regex_result_no_m:{ $regexFind:{ input:'Hello \nWorld!', regex:/^World/ } }, regex_result_m:{ $regexFind:{ input:'Hello \nWorld!!!',regex:/^World/,options:'m' } } }},{$limit:1}])
x、m选项匹配
xxxxxxxxxxdb.students.aggregate([{ $project:{ regex_result_no_x:{ $regexFind:{ input:'Hello World!!!',regex:/He .*/ } }, regex_result_x:{ $regexFind:{ input:'Hello World!!!',regex:/He .*/,options:'x' } }, regex_result_no_s:{ $regexFind:{ input:'Hello \nWorld!!!',regex:/Hello.*ld/ } }, regex_result_s:{ $regexFind:{ input:'Hello \nWorld!!!',regex:/Hello.*ld/,options:'s' } } }},{$limit:1}])
regexFindAll—正则查找符合条件的所有项
版本要求:4.2+
和regexFind的用法一样,只是regexFindAll会找出所有匹配的项
xxxxxxxxxxdb.students.aggregate([{ $project:{ regex_result:{ $regexFind:{ input:'Hello World!!!', regex:/o/ } }, regex_result_all:{ $regexFindAll:{ input:'Hello World!!!', regex:/o/ } } }},{$limit:1}])
regexMatch—判断是否匹配
版本要求:4.2+,和regexFind的用法一样,只是regexMatch匹配成功会返回true,否则返回false
xxxxxxxxxxdb.students.aggregate([{ $project:{ regex_result:{ $regexMatch:{ input:'Hello World!!!', regex:/he/ } }, regex_result_i:{ $regexMatch:{ input:'Hello World!!!',regex:/he/,options:'i' } }, }},{$limit:1}])
replaceOne—替换第一次匹配的字符串
版本要求:4.4+
基础语法
xxxxxxxxxx{ $replaceOne: { input: <expression> 数据源, find: <expression> 查找的字符串, replacement: <expression> 替换的字符串 }}如将学生姓名中的第一个a替换成AAAAA
xxxxxxxxxxdb.students.aggregate([{ $project:{ name:1, name_replace:{ $replaceOne:{ input:'$name', find:'a', replacement:'AAAAA' } } }}])
replaceAll—替换所有匹配的字符串
版本要求:4.4+,和replaceOne用法一致
如将学生姓名中的e全部替换成EEEEE
xxxxxxxxxxdb.students.aggregate([{ $project:{ name:1, name_replace:{ $replaceAll:{ input:'$name', find:'e', replacement:'EEEEE' } } }}])
split—按照某字符切割字符串
xxxxxxxxxxdb.students.aggregate([{ $project:{ split:{ $split:[ 'Hello World!', ' ' ] }, split2:{ $split:[ 'Hello World!', 'o' ] }, }},{$limit:1}])
strcasecmp—对比字符串大小,不区分大小写
A与B进行比较,若A大于B则返回1,相等则返回0,小于则返回-1
xxxxxxxxxxdb.students.aggregate([{ $project:{ strcasecmp_result_equal:{ $strcasecmp:['abc','ABC'] }, strcasecmp_result_great:{ $strcasecmp:['ABCD','abc'] }, strcasecmp_result_less:{ $strcasecmp:['abc','ABCD'] }, }},{$limit:1}])
strLenBytes—获取UTF8编码的字节数
xxxxxxxxxxdb.students.aggregate([{ $project:{ len_bytes_en:{ $strLenBytes:'Hello' }, len_bytes_en_space:{ $strLenBytes:'Hello World!' }, len_bytes_cn:{ $strLenBytes:'你好哇!' }, len_bytes_jp:{ $strLenBytes:'爱してる' }, len_bytes_not:{ $strLenBytes:'cafétéria' } }},{$limit:1}])
strLenCP—返回UTF-8的数量
xxxxxxxxxxdb.students.aggregate([{ $project:{ len_bytes_en:{ $strLenCP:'Hello' }, len_bytes_en_space:{ $strLenCP:'Hello World!' }, len_bytes_cn:{ $strLenCP:'你好哇!' }, len_bytes_jp:{ $strLenCP:'爱してる' }, len_bytes_not:{ $strLenCP:'cafétéria' } }},{$limit:1}])
substr、substrBytes—截取字符串
mongo3.4+后,两个都是一个意思substr是substrBytes的别名,仅仅演示substr
xxxxxxxxxxdb.students.aggregate([{ $project:{ name:1, name_sub:{ $substr:['$name',0,3] } }}])
substrCP—截取字符串
官方例子
不理解
xxxxxxxxxxdb.students.aggregate([{ $project:{ sub_str:{ $substrCP:['abcdEFG',0,2] }, sub_str2:{ $substrCP:['Hello World!',5,5] }, sub_str3:{ $substrCP:['!!!!',2,2] }, sub_str4:{ $substrCP:['cafétéria',4,2] }, sub_str5:{ $substrCP:["€λG",2,3] }, sub_str6:{ $substrCP:['你好',1,1] } }},{$limit:1}])
trim—去除左右两边的指定字符串、默认空格
xxxxxxxxxx{ $trim: { input: <string> 字符串, chars: <string> 去除的指定字符、默认空字符串、可选 } }xxxxxxxxxxdb.students.aggregate([{ $project:{ rtrim_str:{ $rtrim:{input:'Hello World'} }, rtrim_str_ld:{ $trim:{input:'Hello Hello World HeHhHe',chars:'He'} }, rtrim_str_space:{ $trim:{input:' \r\n Hello World\t \r\n '} }, }},{$limit:1}])
数组相关聚合函数
addToSet—返回唯一值数组
仅支持在 $bucket、$bucketAuto、$group、$setWindowField这四个管道中使用
我们这里把Set理解成不重复的数组就很好理解了
如根据sex字段进行分组,并输出对应的年龄和语文成绩
xxxxxxxxxxdb.students.aggregate([{ $group: { _id:'$sex', all_age:{$addToSet:'$age'}, all_sx:{$addToSet:'$score.yw'} }}])
arrayElemAt—获取数组的指定下标值
下标-1即倒数第一个,-2即倒数第二个,依次往下
xxxxxxxxxxdb.students.aggregate([{ $project: { first:{$arrayElemAt:['$favorites',0]}, last:{$arrayElemAt:['$favorites',-1]}, index2:{$arrayElemAt:['$favorites',2]}, 'index-2':{$arrayElemAt:['$favorites',-2]}, }}])
arrayToObject—将数组转换成对象
xxxxxxxxxxdb.students.aggregate([{ $project: { new_arr:{$arrayToObject:'$favorites'} }}])concatArrays—链接数组并返回结果
为每个学生添加 ['pear','bear']
xxxxxxxxxxdb.students.aggregate([{ $project: { score_cmp:{ $concatArrays:[ '$favorites', ['pear','bear'] ] } },}])
filter—过滤数组
基础语法
xxxxxxxxxx{ $filter: { input: 数组, as: 数组里每个元素, cond: 过滤条件 } }查询学生爱好中包含"apples"选项
xxxxxxxxxxdb.students.aggregate([{ $project:{ favorites:1, target_filter:{ $filter:{ input:'$favorites', as:'item', cond:{ $eq:['$$item','apples'] } } } }}])
first—获取第一个元素,常用于数组
版本要求:5.0+,与last取最后元素相对应
仅支持在bucket、bucketAuto、group、setWindowFields阶段中使用
如男生女生各取一名学生信息
xxxxxxxxxxdb.students.aggregate([{ $group:{ _id:'$sex', info:{$first:'$$ROOT'} }}])
in—判断数组是否包含某个元素
如查找喜欢吃“apples”的同学
xxxxxxxxxxdb.students.aggregate([{ $match:{ $expr:{ $in:[ "apples", "$favorites" ] } }},{ $project:{ name:1, favorites:1 }}])
indexOfArray—查询数组中指定元素
查询数组中指定元素,若包含指定元素则返回第一次出现的索引,若不包含则返回-1
基础语法
xxxxxxxxxx{ $indexOfArray: [ <array expression> 数组, <search expression> 指定元素, <start> 开始查找的位置下标、默认0、可选, <end> 结束查找的位置下标、默认结尾、可选] }如查找favorites数组中apples出现的位置
xxxxxxxxxxdb.students.aggregate([{ $project:{ favorites:1, fav_index:{ $indexOfArray:['$favorites',"apples"] }, fav_index_start:{ $indexOfArray:['$favorites',"apples",2] }, fav_index_end:{ $indexOfArray:['$favorites',"apples",0,2] } }}])# fav_index_start 从第三个开始查找(不查找前三个)# fav_index_end 从第1个开始查找,第三个停止查找(只查找前三个)
last—取最后一个文档
版本要求:5.0+,与first取最后元素相对应
仅支持bucket、bucketAuto、group、setWindowFields阶段中使用
xxxxxxxxxxdb.students.aggregate([{ $group:{ _id:'$sex', info:{$last:'$$ROOT'} }}])
last(Array)—取数组中最后一个元素
固定语法:$last:[ 值 ] 注意值外面是用中括号包起来的
xxxxxxxxxxdb.students.aggregate([{ $project:{ last_item:{ $last:[ [1,2,3,4] ] }, last_favorite:{ $last:'$favorites' } }}])
map—遍历操作每个元素,并返回修改后的结果
基础语法,通常操作数组
xxxxxxxxxx{ $map: { input: <expression> 数据源, as: <string> 每个元素, in: <expression> 操作元素 } }如在favorites的每一项前加上"我喜欢"
xxxxxxxxxxdb.students.aggregate([{ $project:{ favorites:'$favorites', favorites_map:{ $map:{ input:'$favorites', as:'item', in:{ $concat:['我喜欢','$$item'] } } } }},{$limit:1}])
objectToArray—对象转成数组
xxxxxxxxxxdb.students.aggregate([{ $project:{ score:1, score_arr:{ $objectToArray:'$score' } }},{$limit:1}])
push—往数组中添加元素
仅支持bucket、bucketAuto、group、setWindowFields阶段中使用
xxxxxxxxxxdb.students.aggregate([{ $group:{ _id:'$sex', name_arr:{ $push:'$name' } }}])
range—获取一批有序数组
基础语法,遵循左闭右开原则
xxxxxxxxxx{ $range: [ <start> 开始, <end> 结束, <non-zero step> 步长、默认1、可选] }xxxxxxxxxxdb.students.aggregate([{ $project:{ range1:{ $range:[0,5] }, range10:{ $range:[10,20,2] }, }},{$limit:1}])
reduce—遍历数组组成一个值
基础语法
xxxxxxxxxx{ $reduce: { input: <array> 数据源, initialValue: <expression> 初始变量, in: <expression> 操作变量,$$value=上次的和,$$this=本次的元素 }}计算从1到10的总积,
xxxxxxxxxxdb.students.aggregate([{ $project:{ sum_multiply:{ $reduce:{ input:{$range:[1,10]}, initialValue:1, in:{ $multiply:['$$this','$$value'] } } } }},{$limit:1}])
reverseArray—将数组前后颠倒
xxxxxxxxxxdb.students.aggregate([{ $project:{ arr_ver:{ $reverseArray:[ [1,2,3,4] ] }, arr_ver_null:{ $reverseArray:[ [1,null] ] }, arr_ver_arr:{ $reverseArray:[ [ [1,2,3], [4,5,6] ] ] }, }},{$limit:1}])
setDifference—比较两个数组,寻找相较于第一个数组的差集
xxxxxxxxxx{ $setDifference: [ <expression1>, <expression2> ]}# 若1中有,而2中没有,则将该结果返回xxxxxxxxxxdb.students.aggregate([{ $project:{ arr_dif:{ $setDifference:[ [1,2,3,4], [5,6,7,8] ] }, arr_dif_1:{ $setDifference:[ [3,4,null,[8]], [7,8,3] ] }, }},{$limit:1}])
setEquals—比较多个数组是否含有相同元素
若多个数组均含有相同元素则返回false,否则返回true,无关顺序
xxxxxxxxxxdb.students.aggregate([{ $project:{ arr_equals:{ $setEquals:[ [1,2,3,4], [5,6,7,8] ] }, arr_equals_1:{ $setEquals:[ [null,0,null,'1'], [null,'1',0,null], ] }, }},{$limit:1}])
setField—添加、修改、移除字段
基础语法
xxxxxxxxxx{ $setField: { field: <String> 字段名称, input: <Object> 对象,$$this表明当前对象 value: <Expression> 值,若值为$$REMOVE,则表示删除该字段 }}setIntersection—比较多个数组,并将交集结果返回
xxxxxxxxxxdb.students.aggregate([{ $project:{ arr_intersection:{ $setIntersection:[ [1,2,3,4], [5,6,7,8] ] }, arr_intersection_1:{ $setIntersection:[ [null,0,null,'1',3,5,8,9], [null,null,3,7,9,1] ] }, arr_intersection_2:{ $setIntersection:[ [3,5,8,9], [3,7], [3,8,9] ] }, }},{$limit:1}])
setIsSubset—比较两个数组判断子集
若第一个数组是第二个数组的子集,则将结果为true,否则为false
xxxxxxxxxxdb.students.aggregate([{ $project:{ arr_subset:{ $setIsSubset:[ [1,2,3,4], [5,6,7,8] ] }, arr_subset_1:{ $setIsSubset:[ [null,0], [null,null,3,7,] ] }, arr_subset_2:{ $setIsSubset:[ [3,8,9], [3,8,9] ] }, }},{$limit:1}])
setUnion—比较多个数组,并将并集结果返回
xxxxxxxxxxdb.students.aggregate([{ $project:{ arr_union:{ $setUnion:[ [1,2,3,4], [5,6,7,8] ] }, arr_union_1:{ $setUnion:[ [null,0], [null,null,3,7,] ] }, arr_union_2:{ $setUnion:[ [3,8,9], [3,8,9] ] }, }},{$limit:1}])
size—获取数组大小
xxxxxxxxxxdb.students.aggregate([{ $project:{ favorites:1, favorites_size:{ $size:'$favorites' } }}])
slice—切割数组
基础语法
xxxxxxxxxx#从第0位开始获取,获取n个{ $slice: [ <array>, <n> ] }#从第position位开始获取,获取n个{ $slice: [ <array>,<position>, <n> ] }xxxxxxxxxxdb.students.aggregate([{ $project:{ favorites:1, favorites_size:{ $slice:['$favorites',2] }, slice_5:{ $slice:[ [1,2,3,4,5,6,7,8,9], 5 ] }, slice_5_3:{ $slice:[ [1,2,3,4,5,6,7,8,9], 5, 3 ] } }},{$limit:1}])
zip—转置数组
基础语法
xxxxxxxxxx{ $zip: { inputs: [ <array expression1>, ... ], useLongestLength: <boolean> 使用inputs中最长的数组长度、不够则补null、可选, defaults: <array expression> 补位、长度要与inputs的长度一致、可选、指定时useLongestLength要为true }}xxxxxxxxxxdb.students.aggregate([{ $project:{ zip:{ $zip:{ inputs:[['a','b','c'],[1,2,3]] } }, zip_long:{ $zip:{ inputs:[['a','b','c'],[1]], useLongestLength:true } }, zip_long_default:{ $zip:{ inputs:[['a','b','c'],[1]], useLongestLength:true, defaults:[2,3] } } }},{$limit:1}])
判断相关操作
and—bool运算且
简单例子
xxxxxxxxxxTrue:true、1、[]、strFalse:false、0、null、undefined{ $and: [ 1, "green" ] } true{ $and: [ ] } true{ $and: [ [ null ], [ false ], [ 0 ] ] } true{ $and: [ null, true ] } false{ $and: [ 0, true ] } false查找语文、数学成绩都超过60(及格)的学生
xxxxxxxxxxdb.students.aggregate([{ $match: { $and:[ {'score.yw':{$gte:60}}, {'score.sx':{$gte:60}}, ] }}])
allElementsTrue—判断所有元素是否全为True
xxxxxxxxxxTrue:true、1、[]、strFalse:false、0、null、undefined官方例子
xxxxxxxxxx# 数据准备db.survey.insertMany([ { "_id" : 1, "responses" : [ true ] }, { "_id" : 2, "responses" : [ true, false ] }, { "_id" : 3, "responses" : [ ] }, { "_id" : 4, "responses" : [ 1, true, "seven" ] }, { "_id" : 5, "responses" : [ 0 ] }, { "_id" : 6, "responses" : [ [ ] ] }, { "_id" : 7, "responses" : [ [ 0 ] ] }, { "_id" : 8, "responses" : [ [ false ] ] }, { "_id" : 9, "responses" : [ null ] }, { "_id" : 10, "responses" : [ undefined ] }])# 查询输出db.survey.aggregate( [ { $project: { responses: 1, isAllTrue: { $allElementsTrue: [ "$responses" ] }, _id: 0 } } ])
anyElementTrue—判断所有元素是否有一个为True
xxxxxxxxxxTrue:true、1、[]、strFalse:false、0、null、undefined官方例子
xxxxxxxxxxdb.survey.aggregate( [ { $project: { responses: 1, isAnyTrue: { $anyElementTrue: [ "$responses" ] }, _id: 0 } } ])
or—bool或运算
True:true、1、[]、str False:false、0、null、undefined
xxxxxxxxxxdb.students.aggregate([{ $match:{ $expr:{ $or:[ {$gte:['$score.sx',60]}, {$eq:['$sex','男']}, ] } }},{ $project:{ name:1, sex:1, sx_score:'$score.sx' }}])
cmp—比较两个数并返回
如a、b,若a大于b则返回1,a小于b则返回-1,a等于b则返回0
xxxxxxxxxxdb.students.aggregate([{ $project: { yw:'$score.yw', sx:'$score.sx', score_cmp:{ $cmp:['$score.yw','$score.sx'] } },}])
cond—条件判断,if else
语法:{ $cond: { if: <boolean-expression>, then: <true-case>, else: <false-case> } }
简写:{ $cond: [ <boolean-expression>, <true-case>, <false-case> ] }
xxxxxxxxxxdb.students.aggregate([{ $project: { evaluate:{ $cond:{ if:{$gte:['$score.sx',60]}, then:'及格', else:'不及格' } } },}])# 或者db.students.aggregate([{ $project: { evaluate:{ $cond:[ {$gte:['$score.sx',60]}, '及格', '不及格' ] } },}])
eq—判断两值相等
相等返回True,否则返回false
xxxxxxxxxxdb.students.aggregate([{ $project:{ age:'$age', age_is_18:{ $eq:['$age',18] }, eq_result:{ $eq:['18',18] }, eq_result2:{ $eq:[null,null] }, }}])
isArray—判断是否为数组类型
固定语法:$isArray:[ 值 ]—注意值外面是用中括号包起来的
xxxxxxxxxxdb.students.aggregate([{ $project:{ isArray:{ $isArray:[ [1,2,3] ] }, isArray2:{ $isArray:[ [[1],2,"3"] ] }, isArray3:{ $isArray:[ 1 ] }, }},{$limit:1}])
isNumber—判断是否为数值类型
若类型为Integer、Decimal、Double、Long都属于数值类型,都返回true,其余都返回false
xxxxxxxxxxdb.students.aggregate([{ $project:{ isNumber:{ $isNumber:1 }, isNumber2:{ $isNumber:NumberDecimal('1.2') }, isNumber3:{ $isNumber:NumberLong('120000000000000000') }, isNumber4:{ $isNumber:true }, isNumber5:{ $isNumber:'111' }, }},{$limit:1}])
ifNull—先判断空值再取值
版本要求:5.0+
如我们要取一个值,若Info字段不为null则取Info,否则取name字段,若name字段为null,则取favorites,我们可以这样写
xxxxxxxxxxdb.students.aggregate([{ $project:{ stu_info:{ $ifNull:["$info","$name","$age"] } }}])
gt、gte—判断数值大于、大于等于某个值
与lt、lte小于、小于等于相对应
xxxxxxxxxxdb.students.aggregate([{ $match:{$expr:{ $gt:['$age',18] }},},{$project:{name:1}}])db.students.aggregate([{ $match:{$expr:{ $gte:['$age',18] }}},{$project:{name:1}}])################################等同于db.students.aggregate([{ $match:{ age:{$gt:18} }},{$project:{name:1}}])
lt、lte—判断数值小于、小于等于某个值
查询年龄小于50且数学成绩小于等于60的学生
xxxxxxxxxxdb.students.aggregate([{ $match:{ $expr:{ $and:[ {$lt:['$age',50]}, {$lte:['$score.sx',60]} ] } }}])ne—比较两数不相等
不相等则返回true,否则返回false,not equal的缩写
如查找数学成绩不等于60的学生
xxxxxxxxxxdb.students.aggregate([{ $match:{ $expr:{ $ne:['$score.sx',60] } }},{ $project:{ name:1, sx_score:'$score.sx' }}])
not—非、不
如查找数学成绩不及格的学生,非大于等于那就是小于的意思
xxxxxxxxxxdb.students.aggregate([{ $match:{ $expr:{ $not:[ {$gte:['$score.sx',60]} ] } }},{ $project:{ name:1, sx_score:'$score.sx' }}])
switch—switch case条件语句
判断数学成绩,给出相应评级
xxxxxxxxxxdb.students.aggregate([{ $project:{ score:'$score.sx', pingyu:{ $switch:{ branches:[ {case:{$gte:['$score.sx',90]},then:'优秀'}, {case:{$gte:['$score.sx',80]},then:'良好'}, {case:{$gte:['$score.sx',60]},then:'及格'}, {case:{$lt:['$score.sx',60]},then:'不及格'}, ], default:'无成绩' } } }}])
类型相关聚合函数
convert—转换类型
to类型:double、string、objectId、bool、date、int、long、decimal 严格区分大小写
xxxxxxxxxxdb.students.aggregate([{ $project: { toInt:{ $convert:{input:'333',to:'int'} }, toDecimal:{ $convert:{input:'3.33',to:'decimal'} }, toObjectId:{ $convert:{input:'625fdc38036ba2d828afdae0',to:'objectId'} }, toBool:{ $convert:{input:'0',to:'bool'} }, toDate:{ $convert:{input:'2022-02-22',to:'date'} }, OnError:{ $convert:{input:'3.33',to:'int',onError:'转换出错,指定转换类型错误'} }, OnNull:{ $convert:{input:null,to:'date',onNull:'输入值为null'} } }}])
toBool—转布尔类型
Double、Decimal、Integer、Long类型若值不为0则返回true,否则返回false
ObjectId、String、Date都会返回true,注意字符串的false也会转成true,有点不理解...
xxxxxxxxxxdb.students.aggregate([{ $project:{ decimal:{$toBool:NumberDecimal('2.2')}, integer:{$toBool:NumberInt('22')}, long:{$toBool:NumberLong('22')}, decimal_0:{$toBool:NumberDecimal('0')}, integer_0:{$toBool:NumberInt('0')}, long_0:{$toBool:NumberLong('0')}, objectId:{$toBool:ObjectId('619d9039ec36b0e8cbfb401c')}, string:{$toBool:'2.2'}, string_true:{$toBool:'true'}, string_false:{$toBool:'false'}, date:{$toBool:ISODate('2020-08-08')}, }},{$limit:1}])
toDate—转时间类型
支持时间戳(毫秒)、字符串、ObjectId转成时间类型
xxxxxxxxxxdb.students.aggregate([{ $project:{ decimal:{$toDate:15330000000.60}, integer:{$toDate:1533600000000}, long:{$toDate:1533657600000}, objectId:{$toDate:ObjectId('619d9039ec36b0e8cbfb401c')}, string:{$toDate:'2018-08-08T08:08:08.888Z'}, string_1:{$toDate:'2018-08-08'}, string_2:{$toDate:'2018-08-08T08:08:08'} }},{$limit:1}])
toDecimal—转换Decimal数值类型
false会返回0,true会返回1,Double、Integer、Long、String均会返回Decimal类型的数值
注意:Sting一定要是数值,不支持objectId类型,Date会返回Decimal类型的时间戳值(ms)
xxxxxxxxxxdb.students.aggregate([{ $project:{ decimal:{$toDecimal:2.2}, integer:{$toDecimal:153}, long:{$toDecimal:1533657600000000000000}, string:{$toDecimal:'08.88'}, string_1:{$toDecimal:'2018'}, bool_false:{$toDecimal:false}, bool_true:{$toDecimal:true}, date:{$toDecimal:ISODate('2018-08-08T08:08:08.888Z')} }},{$limit:1}])
toDouble—转换成Double类型
false会返回0,true会返回1,Decimal、Integer、Long、String均会返回Double类型的数值
注意:Sting一定要是数值,不支持objectId类型,Date会返回Double类型的时间戳值(ms)
xxxxxxxxxxdb.students.aggregate([{ $project:{ decimal:{$toDouble:2.2}, integer:{$toDouble:153}, long:{$toDouble:1533657600000000000000}, string:{$toDouble:'08.88'}, string_1:{$toDouble:'2018'}, bool_false:{$toDouble:false}, bool_true:{$toDouble:true}, date:{$toDouble:ISODate('2018-08-08T08:08:08.888Z')} }},{$limit:1}])
toInt—转换成Integer类型
false会返回0,true会返回1,Decimal、Integer、Long、String均会返回Int类型的数值
注意:Sting一定要是数值、不能包含小数点且不能超过Int的精度范围,不支持objectId、Date类型,Decimal、Double会截断小数点只返回整数、Long类型的值不能超过Int的精度
xxxxxxxxxxdb.students.aggregate([{ $project:{ double:2.2, decimal:{$toInt:NumberDecimal('2.2')}, integer:{$toInt:153}, long:{$toInt:NumberLong('1533657600')}, string:{$toInt:'08'}, string_1:{$toInt:'2018'}, bool_false:{$toInt:false}, bool_true:{$toInt:true} }},{$limit:1}])
toLong—转换成Long类型
false会返回0,true会返回1,Decimal、Integer、Double、String均会返回Long类型的数值
注意:Sting一定要是数值、不能包含小数点且不能超过Long的精度范围,不支持objectId,Decimal、Double会截断小数点只返回整数,Date会返回Long类型的时间戳值(ms)
xxxxxxxxxxdb.students.aggregate([{ $project:{ double:2.2, decimal:{$toLong:NumberDecimal('2.2')}, integer:{$toLong:153}, string:{$toLong:'08'}, string_1:{$toLong:'2018000000000'}, bool_false:{$toLong:false}, bool_true:{$toLong:true}, date:{$toDouble:ISODate('2018-08-08T08:08:08.888Z')} }},{$limit:1}])
toObjectId—转换成ObjectId类型
仅支持String类型,且要可转成ObjectId类型
xxxxxxxxxxdb.students.aggregate([{ $project:{ string:{$toObjectId:'619d9039ec36b0e8cbfb401c'} }},{$limit:1}])
toString—转换成String类型
支持所有类型
xxxxxxxxxxdb.students.aggregate([{ $project:{ double:{$toString:2.2}, decimal:{$toString:NumberDecimal('2.2')}, integer:{$toString:22}, long:{$toString:NumberLong('22')}, objectId:{$toString:ObjectId('619d9039ec36b0e8cbfb401c')}, string:{$toString:'Hello World'}, date:{$toString:ISODate('2018-08-08T08:08:08.888Z')} }},{$limit:1}])
toLower—将字符串转为小写字母
如将学生名字转为小写
xxxxxxxxxxdb.students.aggregate([{ $project:{ name:'$name', name_lower:{ $toLower:'$name' }, name_cn:{ $toLower:'你好' } }}])
toUpper—将字符串转为大写字母
xxxxxxxxxxdb.students.aggregate([{ $project:{ name:'$name', name_lower:{ $toUpper:'$name' }, name_cn:{ $toUpper:'你好' } }}])
type—查看类型
xxxxxxxxxxdb.students.aggregate([{ $project:{ t_double:{$type:2.2}, t_decimal:{$type:NumberDecimal('2.2')}, t_integer:{$type:22}, t_long:{$type:NumberLong('22')}, t_objectId:{$type:ObjectId('619d9039ec36b0e8cbfb401c')}, t_string:{$type:'Hello World'}, t_date:{$type:ISODate('2018-08-08T08:08:08.888Z')}, t_bool:{$type:true}, t_null:{$type:null}, t_undefined:{$type:undefined}, t_regex:{$type:/aaa/}, }},{$limit:1}])
时间相关操作
dateAdd—添加时间
版本要求:5.0+
更多请参考:$dateAdd (aggregation) — MongoDB Manual
startDate:初始时间,可以是时间类型、时间戳类型、ObjectId,但不能直接转换long类型
unit单位:year、quarter、week、month、day、hour、minute、second、millisecond
amount:正数为加,负数为减(dateSubtract效果)
timezone 一直测试不出来...,运行结果不达预期(bug?)
xxxxxxxxxxdb.students.aggregate([{ $project:{ create_at:1, create_at_date:{ $toDate:'$create_at' }, time_now:{ $dateAdd:{ startDate: {$toDate:'$create_at'}, unit: "month", amount: 1 } } }}])
dateDiff—比较两个时间的差
版本要求:5.0+
xxxxxxxxxx{ $dateDiff: { startDate: 时间1, endDate: 时间2, unit: 比较的单位year、quarter、week、month、day、hour、minute、second、millisecond, timezone: 时区、可选参数, startOfWeek: 一周的开始、默认是星期天、可选参数 }}如比较创建时间和最新更新时间,看看两者之间隔了多少月或多少周
xxxxxxxxxxdb.students.aggregate([{ $project:{ diff_month:{ $dateDiff:{ startDate: {$toDate:'$create_at'}, endDate: {$toDate:'$update_at'}, unit: "month" } }, diff_month:{ $dateDiff:{ startDate: {$toDate:'$update_at'}, endDate: {$toDate:'$create_at'}, unit: "month" } }, diff_week_sunday:{ $dateDiff:{ startDate: ISODate('2018-08-08'), endDate: ISODate('2020-08-08'), unit: "week" } }, diff_week_friday:{ $dateDiff:{ startDate: ISODate('2018-08-08'), endDate: ISODate('2020-08-08'), unit: "week", startOfWeek:'friday' } } }}])
dateFromParts—根据指定时间参数转换为时间类型
xxxxxxxxxx{ $dateFromParts : { 'year': <year> 必填, 'month': <month> 1-12, 'day': <day> 1-31, 'hour': <hour> 0-23, 'minute': <minute> 0-59, 'second': <second> 0-59, 'millisecond': <ms> 0-999, 'timezone': <tzExpression> }}或者{ $dateFromParts : { 'isoWeekYear': <year> 必填, 'isoWeek': <week> 0-55, 'isoDayOfWeek': <day> 1-7, 'hour': <hour>, 'minute': <minute>, 'second': <second>, 'millisecond': <ms>, 'timezone': <tzExpression> }}year和month是固定出现的,isoWeekYear、isoWeek、isoDayOfWeek也是固定出现的不能混起来使用
xxxxxxxxxxdb.students.aggregate([{ $project:{ time_year:{ $dateFromParts:{'year':2018,'month':8,'day':8} }, time_isoYear:{ $dateFromParts:{'isoWeekYear':2018,'isoWeek':8,'isoDayOfWeek':1} } }},{$limit:1}])
dateFromString—从字符串转换成事件类型
xxxxxxxxxx{ $dateFromString: { dateString: 时间字符串, format: dateString 的格式、可选, timezone: 时区、可选, onError: 转换失败处理、可选, onNull: 转换空值处理、可选 } }# 2018-08-08T08:08:08.888# %Y-%m-%dT%H-%M-%S.%L# %Y:year %m:month %d:day %H:hour %M:minute %S:second %L:milliSecond# %G:ISOYear %u:DayofWeek %V:WeekOfYear %z:时区间隔 %Z:失去间隔 %%:%符号# mongodb又自己搞了一套format,就不能统一一下吗xxxxxxxxxxdb.students.aggregate([{ $project:{ time1:{ $dateFromString:{dateString:'2018-08-08T08:08:08.888'} }, time2:{ $dateFromString:{dateString:"2021/8/18"} }, time_error:{ $dateFromString:{ dateString:"06-15-2018", onError:'转换失败' } }, time_format:{ $dateFromString:{ dateString:"06-15-2018", format:'%m-%d-%Y' } }, time_numm:{ $dateFromString:{ dateString:null, onNull:'空值' } } }},{$limit:1}])
dateSubtract—递减时间
版本要求:5.0+
startDate:初始时间,可以是时间类型、时间戳类型、ObjectId,但不能直接转换long类型
unit单位:year、quarter、week、month、day、hour、minute、second、millisecond
amount:正数为减,负数为加(dateAdd效果)
xxxxxxxxxxdb.students.aggregate([{ $project:{ create_at:1, create_at_date:{ $toDate:'$create_at' }, time_next_month:{ $dateSubtract:{ startDate: {$toDate:'$create_at'}, unit: "month", amount: -1 } }, time_last_month:{ $dateSubtract:{ startDate: {$toDate:'$create_at'}, unit: "month", amount: 1 } }, }}])
dateToParts—将时间解析成各个时间组成部分
将一个时间类型的值返回year、month、day、hour、minute、second、millisecond,若指定了iso8601为true,则会返回isoWeekYear、isoWeek、 isoDayOfWeek、hour、minute、second、millisecond。
xxxxxxxxxxdb.students.aggregate([{ $project:{ date_parts:{ $dateToParts:{ date:{$toDate:'$create_at'} } }, date_iso_parts:{ $dateToParts:{ date:{$toDate:'$create_at'}, iso8601:true } }, date_zone_parts:{ $dateToParts:{ date:{$toDate:'$create_at'}, timezone:'+0800' } }, }},{$limit:1}])
dateToString—日期转字符串
xxxxxxxxxx{ $dateToString: { date: 要转换的时间, format: 转换格式、可选, timezone: 时区、可选, onNull: 为null时处理、可选 } }# 2018-08-08T08:08:08.888# %Y-%m-%dT%H-%M-%S.%L# %Y:year %m:month %d:day %H:hour %M:minute %S:second %L:milliSecond# %G:ISOYear %u:DayofWeek %V:WeekOfYear %z:时区间隔 %Z:失去间隔 %%:%符号xxxxxxxxxxdb.students.aggregate([{ $project:{ date_str:{ $dateToString:{ date:{$toDate:'$create_at'} } }, date_format_str:{ $dateToString:{ date:{$toDate:'$create_at'}, format:'%d-%m-%Y' } }, date_zone_str:{ $dateToString:{ date:{$toDate:'$create_at'}, timezone:'+0800' } }, date_null_str:{ $dateToString:{ date:null, onNull:'为空值' } } }},{$limit:1}])
dateTrunc—截断日期
版本要求:v5.0+ 参考:$dateTrunc (aggregation) — MongoDB Manual
unit可指定:
year——当年的1月1日,无时间
quarter——当年当季的第一月1日,无时间
week——当年当周的第一天,无时间
month——当年当月1日,无时间
day——当年当月当日,无时间
hour——当年当月当日当时,无分秒
minute——当年当月当日当时分,无秒
second——当年当月当日当时分秒,无毫秒
binSize 一直没试成功,运行结果和自己预期的结果大相径庭,但又不知道怎么回事(bug?)
xxxxxxxxxxdb.students.aggregate([{ $project:{date_now:new Date("2020-05-18T14:10:30.888Z")}},{ $project:{ trunc_s:{ $dateTrunc:{date:'$date_now',unit:'second'} }, trunc_s2:{ $dateTrunc:{date:'$date_now',unit:'second', binSize:30} }, trunc_s3:{ $dateTrunc:{date:'$date_now',unit:'second', binSize:60} } }},{$limit:1}])
xxxxxxxxxxdb.students.aggregate([{ $project:{date_now:new Date("2020-05-18T14:10:30.888Z")}},{ $project:{ trunc_m:{ $dateTrunc:{date:'$date_now',unit:'minute'} }, trunc_m2:{ $dateTrunc:{date:'$date_now',unit:'minute', binSize:10} }, trunc_m3:{ $dateTrunc:{date:'$date_now',unit:'minute', binSize:60} }, trunc_h:{ $dateTrunc:{date:'$date_now',unit:'hour'} }, trunc_h2:{ $dateTrunc:{date:'$date_now',unit:'hour', binSize:14} }, trunc_h3:{ $dateTrunc:{date:'$date_now',unit:'hour', binSize:24} } }},{$limit:1}])
xxxxxxxxxxdb.students.aggregate([{ $project:{date_now:new Date("2020-05-18T14:10:30.888Z")}},{ $project:{ trunc_d:{ $dateTrunc:{date:'$date_now',unit:'quarter'} }, trunc_d2:{ $dateTrunc:{date:'$date_now',unit:'quarter',binSize:2} }, trunc_m:{ $dateTrunc:{date:'$date_now',unit:'week'} }, trunc_m2:{ $dateTrunc:{date:'$date_now',unit:'week',binSize:10} }, trunc_y:{ $dateTrunc:{date:'$date_now',unit:'year'} }, trunc_y2:{ $dateTrunc:{date:'$date_now',unit:'year',binSize:10} } }},{$limit:1}])
xxxxxxxxxxdb.students.aggregate([{ $project:{date_now:new Date("2020-05-18T14:10:30.888Z")}},{ $project:{ trunc_q:{ $dateTrunc:{date:'$date_now',unit:'day'} }, trunc_q2:{ $dateTrunc:{date:'$date_now',unit:'day',binSize:18} }, trunc_q3:{ $dateTrunc:{date:'$date_now',unit:'day',binSize:31} }, trunc_w:{ $dateTrunc:{date:'$date_now',unit:'month'} }, trunc_w2:{ $dateTrunc:{date:'$date_now',unit:'month',binSize:5} }, trunc_w3:{ $dateTrunc:{date:'$date_now',unit:'month',binSize:12} } }},{$limit:1}])
dayOfMonth—查询一月之中的第几天、0-31
xxxxxxxxxxdb.students.aggregate([{ $project:{ day:{ $dayOfMonth:{ date:{$toDate:'$create_at'} } }, day_timezone:{ $dayOfMonth:{ date:{$toDate:'$create_at'}, timezone:'+0800' } }, }}])
dayOfWeek—查询一周之中的第几天,1-7
xxxxxxxxxxdb.students.aggregate([{ $project:{ day_week:{ $dayOfWeek:{ date:{$toDate:'$create_at'} } }, day_week_timezone:{ $dayOfWeek:{ date:{$toDate:'$create_at'}, timezone:'+0800' } }, }}])
dayOfYear—查询一年之中的第几天,0-365
xxxxxxxxxxdb.students.aggregate([{ $project:{ day_Year:{ $dayOfYear:{ date:{$toDate:'$create_at'} } }, day_Year_timezone:{ $dayOfYear:{ date:{$toDate:'$create_at'}, timezone:'+0800' } }, }}])
hour—获取时间中的小时值
xxxxxxxxxxdb.students.aggregate([{ $project:{ date:{$toDate:'$create_at'} }},{ $project:{ date:'$date', date_hour:{ $hour:'$date' }, date_hour_timezone:{ $hour:{ date:'$date', timezone:'+0800' } } }}])
isoDayOfWeek—ISO 查询一周之中的第几天,1-7
xxxxxxxxxxdb.students.aggregate([{ $project:{ date:{$toDate:'$create_at'}, day:{ $isoDayOfWeek:{ date:{$toDate:'$create_at'} } }, day_timezone:{ $isoDayOfWeek:{ date:{$toDate:'$create_at'}, timezone:'+0800' } }, }}])
isoWeek—ISO 查询一年之中的第几周,1-53
xxxxxxxxxxdb.students.aggregate([{ $project:{ date:{$toDate:'$create_at'}, day:{ $isoWeek:{ date:{$toDate:'$create_at'} } }, day_timezone:{ $isoWeek:{ date:{$toDate:'$create_at'}, timezone:'+0800' } }, }}])
isoWeekYear—ISO 查询年份
xxxxxxxxxxdb.students.aggregate([{ $project:{ date:{$toDate:'$create_at'}, day:{ $isoWeekYear:{ date:{$toDate:'$create_at'} } }, day_timezone:{ $isoWeekYear:{ date:{$toDate:'$create_at'}, timezone:'+0800' } }, }}])
millisecond—获取某个时间的毫秒值,0-999
xxxxxxxxxxdb.students.aggregate([{ $project:{ date_milli:{ $millisecond:ISODate('2018-08-08T08:08:08.888') }, date_milli_timezone:{ $millisecond:{ date:ISODate('2018-08-08T08:08:08.888'), timezone:'+0800' } } }},{$limit:1}])
minute—获取某个时间的分钟值,0-59
xxxxxxxxxxdb.students.aggregate([{ $project:{ date_minute:{ $minute:ISODate('2018-08-08T08:08:08.888') }, date_minute_timezone:{ $minute:{ date:ISODate('2018-08-08T08:08:08.888'), timezone:'+0800' } } }},{$limit:1}])
month—获取某个时间的月份值,1-12
xxxxxxxxxxdb.students.aggregate([{ $project:{ date_month:{ $month:ISODate('2018-08-08T08:08:08.888') }, date_month_timezone:{ $month:{ date:ISODate('2018-08-08T08:08:08.888'), timezone:'+0800' } } }},{$limit:1}])
second—获取某个时间的秒值,0-59
xxxxxxxxxxdb.students.aggregate([{ $project:{ date_second:{ $second:ISODate('2018-08-08T08:08:08.888') }, date_second_timezone:{ $second:{ date:ISODate('2018-08-08T08:08:08.888'), timezone:'+0800' } } }},{$limit:1}])
week—获取某个时间的周值,0-53
周从星期日开始,第 1 周从一年中的第一个星期日开始。一年中第一个星期日之前的日子在第 0 周
支持Timestamp、Date、ObjeciID
xxxxxxxxxxdb.students.aggregate([{ $project:{ date_week_date:{ $week:ISODate('2018-08-08T08:08:08.888') }, date_week_date_timezone:{ $week:{ date:ISODate('2018-08-08T08:08:08.888'), timezone:'+0800' } }, date_week_id:{ $week:ObjectId('626b4907965f099c1c7d901f') }, date_week_TimeStamp:{ $week:Timestamp(1651075200,0) }, }},{$limit:1}])
year—获取某个时间的年份值,0-9999
xxxxxxxxxxdb.students.aggregate([{ $project:{ date_second:{ $year:ISODate('2018-08-08T08:08:08.888') }, date_second_timezone:{ $year:{ date:ISODate('2018-08-08T08:08:08.888'), timezone:'+0800' } } }},{$limit:1}])
文档相关
count—获取文档总数
版本要求:5.0+
仅支持在 $bucket、$bucketAuto、$group、$setWindowField这四个管道中使用
如分组后获取总数
xxxxxxxxxxdb.students.aggregate([{ $group:{ _id:'$sex', count:{$count:{}} }}])
documentNumber—返回文档在 $setWindowFields 阶段分区中的位置(称为文档编号)
版本要求:5.0+
仅支持在setWindowFields阶段中使用,不知道有什么用...
xxxxxxxxxxdb.students.aggregate([{ $project:{sex:1,age:1}},{ $setWindowFields:{ partitionBy:'$sex', sortBy:{age:-1}, output:{ result:{ $documentNumber: {} } } }}])
getField—获取某个字段的值
版本要求:5.0+,常用于处理含有.、$的字段
xxxxxxxxxx{ $getField: { field: <String>, input: <Object>、默认$$CURRENT、可选 }}官方例子
xxxxxxxxxx# 插入数据db.inventory.insertMany( [ { "_id" : 1,"price.usd": 45.99,"quantity": { "$small": 25}}, { "_id" : 2,"price.usd": 499.99,"quantity": { "$small": 35}}] )# 删除数据db.inventory.drop()查询价格超过50的,并输出小号的数量
xxxxxxxxxxdb.inventory.aggregate([{ $match:{ $expr:{ $gt:[ {$getField:{field:'price.usd',input:'$$CURRENT'}}, 50 ] } }},{ $project:{ all_info:'$$ROOT', small_size:{ $getField:{ field:{$literal:"$small"}, input:'$quantity' } } }}])
let—声明变量操作变量
基础语法
xxxxxxxxxx{ $let: { vars: { <var1>: <expression>, ... 声明变量}, in: <expression> 操作变量 }}如获取语文、数学成绩总和然后判断总分评级,超过150则为优秀,否则为良好
xxxxxxxxxxdb.students.aggregate([{ $project:{ ping_yu:{ $let:{ vars:{ total_score:{ $add:['$score.yw','$score.sx'] } }, in:{ $cond:{ if:{$gt:['$$total_score',150]}, then:{$concat:['总分:',{$toString:'$$total_score'},',','优秀']}, else:{$concat:['总分:',{$toString:'$$total_score'},',','良好']}, } } } } }}])
literal—返回一个不进行解析的值
常用于含有.、$、1的字段,相当于一个转义符,在literal中.、$、1仅仅是个字符串,无特殊意义
官方例子
x# 插入数据db.inventory.insertMany( [ { "_id" : 1,"price.usd": 45.99,"quantity": { "$small": 25}}, { "_id" : 2,"price.usd": 499.99,"quantity": { "$small": 35}}] )# 获取$small的尺码,默认输出订单数为1,在价格前面加$美元符号,并判断价格为$45.99的数据db.inventory.aggregate([{ $project:{ small_size_literal:{ $getField:{ field:{$literal:'$small'}, input:'$quantity' } }, order_literal:{ $literal:1 }, price_literal:{ $concat:[ {$literal:'$'}, { $toString:{ $getField:{ field:'price.usd', input:'$$CURRENT' } } } ] } }},{ $match:{ $expr:{ $eq:[ '$price_literal', {$literal:'$45.99'} ] } }}])# 删除数据db.inventory.drop()
mergeObjects—将多个文档合并为一个文档
仅支持bucket、bucketAuto、group、replaceRoot阶段中使用
若文档中有相同元素则以最后一个文档为主,不同元素会合并为一个对象
合并相同元素,如根据性别分组后合并成绩
xxxxxxxxxxdb.students.aggregate([{ $group:{ _id:'$sex', score_all:{ $push:'$score' }, score_merge:{ $mergeObjects:'$score' } }}])
合并不同元素——将合并后的成绩加个日期
xxxxxxxxxxdb.students.aggregate([{ $group:{ _id:'$sex', score_merge:{ $mergeObjects:'$score' } }},{ $replaceRoot:{ newRoot:{ $mergeObjects:["$score_merge",{'date':'2022-02-02'}] } }}])
meta—查看文档与索引的匹配分数
可设置:
textScore,必须与$text全文索引一起使用,否则会报错,v4.4以下版本会返回null,不会报错
indexKey,如果使用非文本索引,则返回文档的索引键,版本要求v4.4+
没看出来有什么用...
xxxxxxxxxx#创建俩索引db.students.createIndex({name:'text'})db.students.createIndex({age:1})
xxxxxxxxxxdb.students.aggregate([{ $match:{$text:{$search:'tom'}}},{ $project:{ score:{ $meta:'textScore' } }}])
xxxxxxxxxxdb.students.aggregate([{ $match:{ age:{$gt:18} }},{ $project:{ indexKey:{ $meta:'indexKey' } }}])
sampleRate—按照几率随机采样文档
版本要求:4.4.2+
xxxxxxxxxxdb.students.aggregate([{ $match:{ $sampleRate:0.3 }}])
unsetField—删除查询文档结果中的字段
通常用于含有$、.的字段,常与replaceWith一起使用
官方例子
# 准备数据db.inventory.insertMany( [ { _id: 1, item: "sweatshirt", qty: 300, "price.usd": 45.99 }, { _id: 2, item: "winter coat", qty: 200, "price.usd": 499.99 }, { _id: 3, item: "sun dress", qty: 250, "price.usd": 199.99 }, { _id: 4, item: "leather boots", qty: 300, "price.usd": 249.99 }, { _id: 5, item: "bow tie", qty: 180, "price.usd": 9.99 } ] ) # 查询数据db.inventory.aggregate( [ { $replaceWith: { $unsetField: { field: "price.usd", input: "$$ROOT" } } } ] ) # 删除inventory db.inventory.drop()