初识MongoDB(十二) MongoDB管道操作符一

熟悉Linux系统的小伙伴应该知道Linux中有管道的说法,可以用来方便地处理数据。

MongoDB 2.2版本也引入了新的数据聚合框架,一个文档可以经过多个节点组成的管道,每个节点都有自己特殊的功能,比如文档分组、文档过滤等。每一个节点都会接收一连串的文档,对这些文档做一些类型转换,然后将转换后的文档传递给下一个节点,最后一个节点则会将结果返回给客户端。本文先来看几个基本的管道操作符。

$match

$match 可以用来对文档进行筛选。筛选完成之后,我们就可以在筛选获得到的文档子集上做数据聚合操作了。我们之前介绍的查询的操作符在 $match 中都可以使用,比如获取集合中所有 author为"杜甫"的文档,如下:

db.agg_1.aggregate({$match:{author:"杜甫"}})

我们在实际使用时最好将 $match 放在管道的前面,这样可以减少后边管道的工作量。同时,我们在投射和分组之前执行 $match 还可以用索引。

$project

基本用法

$project可以用来提取想要的字段,如下:

db.agg_1.aggregate({$project:{title:1,_id:0}})

1表示要该字段,0表示不要该字段。也可以对返回的字段进行重命名,比如将 title 改为 articleTitle ,如下:

db.agg_1.aggregate({$project:{"articleTitle":"$title"}})

不过这里有一个问题需要注意:如果原字段上有索引,重命名之后的字段上就没有索引了,因此最好在重命名之前使用索引。

数学表达式

数学表达式可以用来对一组数值进行加减乘除取模,比如我的数据结构如下:

{
    "_id":ObjectId("61a71128fcabfe7d198aac94"),
    "orderAddressL":"shenzhen",
    "prodMoney":45,
    "freight":13,
    "discounts":3,
    "orderDate":ISODate("2021-12-01T06:07:36.517Z"),
    "prods":[
        "可乐",
        "奶茶"
    ]
}

订单的总费用为商品费用加上运费,查询如下:

db.agg_2.aggregate({$project:{totalMoney:{$add:["$prodMoney","$freight"]}}})

实际付款的费用是总费用减去折扣,如下:

db.agg_2.aggregate({$project:{totalPay:{$subtract:[{$add:["$prodMoney","$freight"]},"$discounts"]}}})

再来三个无厘头运算,比如计算 prodMoney 和 freight 和 discounts 的乘积,如下:

db.agg_2.aggregate({$project:{test1:{$multiply:["$prodMoney","$freight","$discounts"]}}})

再比如求 prodMoney 和 freight 的商,如下:

db.agg_2.aggregate({$project:{test2:{$divide:["$prodMoney","$freight"]}}})

再比如用 freight 对 prodMoney 取模,如下:

db.agg_2.aggregate({$project:{test3:{$mod:["$freight","$prodMoney"]}}})

加法和乘法都可以接收多个参数,其余的都接收两个参数。

日期表达式

日期表达式可以从一个日期类型中提取出年、月、日、星期、时、分、秒等信息,如下:

db.agg_2.aggregate({$project:{"年份":{$year:"$orderDate"},
"月份":{$month:"$orderDate"},"一年中第几周":{$week:"$orderDate"},
"日期":{$dayOfMonth:"$orderDate"},"星期":{$dayOfWeek:"$orderDate"},
"一年中第几天":{$dayOfYear:"$orderDate"},"时":{$hour:"$orderDate"},
"分":{$minute:"$orderDate"},"秒":{$second:"$orderDate"},
"毫秒":{$millisecond:"$orderDate"},
"自定义格式化时间":{$dateToString:{format:"%Y年%m月%d日 %H:%M:%S",date:"$orderDate"}}}})

执行结果如下:

{
    "_id":ObjectId("61a71128fcabfe7d198aac94"),
    "年份":2021,
    "月份":12,
    "一年中第几周":48,
    "日期":1,
    "星期":4,
    "一年中第几天":335,
    "时":6,
    "分":7,
    "秒":36,
    "毫秒":517,
    "自定义格式化时间":"2021年12月01日 06:07:36"
}

$dayOfWeek 返回的是星期,1表示星期天,7表示星期六。$week 表示本周是本年的第几周,从0开始计。$dateToString 是MongoDB 3.0+中的功能,格式化的字符还有以下几种:

字符 含义 取值范围
%Y Year (4 digits, zero padded) 0000-9999
%m Month (2 digits, zero padded) 01-12
%d Day of Month (2 digits, zero padded) 01-31
%H Hour (2 digits, zero padded, 24-hour clock) 00-23
%M Minute (2 digits, zero padded) 00-59
%S Second (2 digits, zero padded) 00-59
%L Millisecond (3 digits, zero padded) 000-999
%j Day of Year (3 digits, zero padded) 001-366
%w Day of Week (1-Sunday,7-Saturday) 1-7
%U Week of Year (2 digits, zero padded) 00-53

字符串表达式

字符串表达式中有字符串的截取、拼接、转大写、转小写等操作,比如我截取 orderAddressL 前两个字符返回,如下:

db.agg_2.aggregate({$project:{addr:{$substr:["$orderAddressL",0,2]}}})

再比如我将 orderAddressL 和 orderDate 拼接后返回:

db.agg_2.aggregate({$project:{test1:{$concat:["$orderAddressL",{$dateToString:{format:"%Y年%m月%d日 %H:%M:%S",date:"$orderDate"}}]}}})

再比如我将 orderAddressL 全部转为小写返回:

db.agg_2.aggregate({$project:{test1:{$toLower:"$orderAddressL"}}})

再比如我将 orderAddressL 全部转为大写返回:

db.agg_2.aggregate({$project:{test1:{$toUpper:"$orderAddressL"}}})

逻辑表达式

想要比较两个数字的大小,可以使用 $cmp 操作符,如下:

db.agg_2.aggregate({$project:{test1:{$cmp:["$freight","$discounts"]}}})

如果第一个参数大于第二个参数返回正数,第一个参数小于第二个参数则返回负数。也可以利用 $strcasecmp 来比较字符串(中文无效):

db.agg_2.aggregate({$project:{test1:{$strcasecmp:["$orderAddressL",{$dateToString:{format:"%Y年%m月%d日",date:"$orderDate"}}]}}})

至于我们之前介绍的 $eq / $ne / $gt / $gte / $lt / $lte 等操作符在这里一样是适用的。另外还有 $and、$or、$not 等表达式可用,以 $and 为例,如下:

db.agg_2.aggregate({$project:{test1:{$and:[{$eq:["$freight","$prodMoney"]},{$eq:["$freight","$discounts"]}]}}})

$and 中的每个参数都为 true 时返回 true。$or 则表示参数中有一个为 true 就返回 true。$not 则会对它的参数的值取反,如下:

db.agg_2.aggregate({$project:{test1:{$not:{$eq:["$freight","$discounts"]}}}})

另外还有两个流程控制语句,如下:

db.agg_2.aggregate({$project:{test1:{$cond:[false,"trueExp","falseExp"]}}})

$cond 第一个参数如果为 true,则返回 trueExp,否则返回 falseExp。

db.agg_2.aggregate({$project:{test1:{$ifNull:[null,"replacementExp"]}}})

$ifNull 第一个参数如果为 null,就返回 replacementExp,否则就返回第一个参数。

上一篇:TCSVT-2019-基于卷积神经网络的增强双向预测


下一篇:CSDN 十大技术主题盘点-低代码篇