MongoDB体系六(聚合).

图片 1

 一、概念

   
使用聚合框架能够对聚聚集的文书档案举行调换和整合。基本上,可以用多少个零件创制二个管道(pipeline),用于对数不胜数的文书档案进行拍卖。这么些零部件包涵筛选(filtering)、投射(projecting)、分组(grouping)、排序(sorting)、节制(limiting)和跳过(skipping)。

二、聚合函数

db.driverLocation.aggregate(
    {"$match":{"areaCode":"350203"}},
    {"$project":{"driverUuid":1,"uploadTime":1,"positionType":1}},
    {"$group":{"_id":{"driverUuid":"$driverUuid","positionType":"$positionType"},"uploadTime":{"$first":{"$year":"$uploadTime"}},"count":{"$sum":1}}},
    {"$sort":{"count":-1}},
    {"$limit":100},
    {"$skip":50}
)

   
 管道操作符是遵纪守法书写的次第依次实施的,各种操作符都会接受三番三遍串的文书档案,对这个文书档案做一些类型转变,最终将转移后的文书档案作为结果传递给下贰个操作符(对于最终一个管道操作符,是将结果回到给客商端),称为流式专门的职业情势。

 
  超越百分之三十操作符的做事措施都以流式的,只要有新文书档案步入,就可以对新文书档案进行处理,可是”$group”
和 “$sort”
一定要等收到全体的文书档案之后,工夫对文书档案举办分组排序,然后技术将次第分组发送给管道中的下四个操作符。那代表,在分片的情事下,”$group”

“$sort”会先在各种分片上施行,然后挨门挨户分片上的分组结果会被发送到mongos再扩充最终的联合分组,剩余的管道专门的学业也都是在mongos(实际不是在分片)上运营的。

 
  不相同的管道操作符能够按专断顺序组合在黄金年代道行使,何况能够被重复放肆多次。例如,能够先做”$match”,然后做”$group”,然后再做”$match”(与之前的”$match”匹配分裂的询问条件)。

    $田野同志name”语法是为着在会集框架中援引田野name字段。

  • 筛选(filtering)—> $match

   
用于对文档集结进行筛选,之后就足以在筛选拿到的文书档案子集上做聚合。举个例子,如若想对Oregon(内布拉斯加州,简写为O奇骏)的客商做计算,就可以运用{$match
: {“state”
:”OPRADO”}}。”$match”能够动用全数正规的查询操作符(”$gt”、”$lt”、”$in”等)。有多少个不后生可畏必要注意:不能够在”$match”中使用地理空间操作符。
   
常常,在实际上利用中应有尽大概将”$match”放在管道的先头地点。那样做有五个好处:一是能够火速将无需的文书档案过滤掉,以调整和减弱管道的工作量;二是倘若在酷炫和分组在此以前实施”$match”,查询能够行使索引。

  • 投射(projecting)—> $project

    那个语法与查询中的字段接收器比较像:能够经过点名 {“田野name” :
1} 选拔要求投射的字段,或许通过点名 { “田野先生name”:0 }
扑灭无需的字段。实施完那几个”$project”操作之后,结果聚焦的每种文书档案都会以{“_id”
: id, “田野(field卡塔尔(قطر‎name”
:”xxx”}那样的样式表示。那个结果只会在内存中设有,不会被写入磁盘。

    还能对字段实行重命名:db.users.aggregate({“$project” : {“userId” :
“$_id”, “_id” : 0}}卡塔尔,在对字段实行重命名时,MongoDB并不会记录字段的历史名称。

  • 分组(grouping)—> $group

   
 要是选定了亟待开展分组的字段,就足以将选定的字段传递给”$group”函数的”_id”字段。对于地点的例子:大家接受了driverUuid
和 positionType
当作大家分组的标准(当然只选用叁个字段也是能够的)。分组过后,文书档案的
driverUuid 和 positionType 组成的目的就改为了文书档案的唯后生可畏标记(_id)。

图片 1

  “count”:{“$sum”:1}
是为分组内种种文书档案的”count”字段加1。注意,新步向的文书档案中并不会有”count”字段;这”$group”创设的多个新字段。  

  • 排序(sorting)—> $sort

    排序方向能够是1(升序)和 -1(降序)。  

 
 能够依附此外字段(或然四个字段)进行排序,与在日常查询中的语法相近。借使要对大气的文书档案举办排序,刚毅提议在管道的率先品级举行排序,当时的排序操作能够行使索引。不然,排序进程就能异常的慢,况兼会占领多量内部存款和储蓄器。

  • 限制(limiting)—> $limit

   $limit会采纳三个数字n,重回结果集中的前n个文书档案。

  • 跳过(skipping)—> $skip

 
 
$skip也是经受二个数字n,甩掉结果集中的前n个文书档案,将剩余文书档案作为结果重临。在“普通”查询中,如若急需跳过一大波的多少,那么那个操作符的频率会十分低。在聚聚焦也是这么,因为它必定要先相配到全体要求跳过的文书档案,然后再将这一个文书档案吐弃。

  • 拆分(unwind)—> $unwind

   能够将数组中的每二个值拆分为单独的文档。

   譬如文书档案:{ “_id” : 1, “item” : “ABC1”, sizes: [ “S”, “M”, “L”] }

   聚合运算:db.inventory.aggregate( [ {
$unwind : “$sizes” } ] )

   结果:

{ “_id” : 1, “item” : “ABC1”, “sizes” : “S” }
{ “_id” : 1, “item” : “ABC1”, “sizes” : “M” }
{ “_id” : 1, “item” : “ABC1”, “sizes” : “L” }

Spring Data MongoDB 中利用聚合函数:

    /**
     * db.driverLocation.aggregate(
     *     {"$match":{"areaCode":"350203"}},
     *     {"$project":{"driverUuid":1,"uploadTime":1,"positionType":1}},
     *     {"$group":{"_id":{"driverUuid":"$driverUuid","positionType":"$positionType"},"uploadTime":{"$first":{"$year":"$uploadTime"}},"count":{"$sum":1}}},
     *     {"$sort":{"count":-1}},
     *     {"$limit":100},
     *     {"$skip":50}
     * )
     */
    @Test
    public void test04(){
        //match
        Criteria criteria = Criteria.where("350203").is("350203");
        AggregationOperation matchOperation = Aggregation.match(criteria);
        //project
        AggregationOperation projectionOperation = Aggregation.project("driverUuid", "uploadTime", "positionType");
        //group
        AggregationOperation groupOperation = Aggregation.group("driverUuid", "positionType")
                .first(DateOperators.dateOf("uploadTime").year()).as("uploadTime")
                .count().as("count");
        //sort
        Sort sort = new Sort(Sort.Direction.DESC, "count");
        AggregationOperation sortOperation = Aggregation.sort(sort);
        //limit
        AggregationOperation limitOperation = Aggregation.limit(100L);
        //skip
        AggregationOperation skipOperation = Aggregation.skip(50L);

        Aggregation aggregation = Aggregation.newAggregation(matchOperation, projectionOperation, groupOperation, sortOperation, limitOperation, skipOperation);
        AggregationResults<Object> driverLocation = mongoOperations.aggregate(aggregation, "driverLocation", Object.class);
        List<Object> mappedResults = driverLocation.getMappedResults();

    }

 

三、聚合管道操作符

   
MongoDB提供了成都百货上千的操作符用来文书档案聚合后字段间的演算也许分组内的总结,比方上文提到的$sum、$first、$year
等。MongoDB提供了席卷分组操作符、数学操作符、日期操作符、字符串表明式
等等 后生可畏雨后冬笋的操作符…

  • 分组操作符

相像 SQL中分组后的操作,只适用于分组后的计算职业,不适用于单个文书档案。

  1. {“$sum” : value}  对于分组中的每贰个文书档案,将value与总结结果相加。
  2. {“$avg” : value} 再次来到各样分组的平均值
  3. {“$max” : expr} 重返分组内的最大值。
  4. {“$min” : expr} 再次来到分组内的细微值。
  5. {“$first” : expr}
    再次回到分组的率先个值,忽视前边全数值。独有排序之后,鲜明掌握数码顺序时那一个操作才有含义。
  6. {“$last” : expr} 与”$first”相反,重返分组的最后三个值。
  7. {“$addToSet” : expr} 针对数组字段, 假使当前数组中不包涵expr
    ,那就将它增加到数组中。在回到结果集中,每一种成分最多只现身一遍,并且成分的大器晚成一是不分明的。
  8. {“$push” : expr}
    针对数组字段,不管expr是何许值,都将它增添到数组中。重回包涵全数值的数组。
  • 数学操作符

适用于单个文书档案的演算。

  1. {“$add” : [expr1[, expr2, …, exprN]]}
    这些操作符选用三个或四个表明式作为参数,将那么些表达式相加。
  2. {“$subtract” : [expr1, expr2]}
    选拔四个表达式作为参数,用第八个表达式减去第二个表明式作为结果。
  3. {“$multiply” : [expr1[, expr2, …, exprN]]}
    选择三个只怕多个表明式,而且将它们相乘。
  4. {“$divide” : [expr1, expr2]}
    选用四个表明式,用第3个表明式除以第一个表明式的商作为结果。
  5. {“$mod” : [expr1, expr2]}
    接纳多个表明式,将率先个表明式除以第三个表明式获得的余数作为结果。
  • 字符串表明式

适用于单个文书档案的运算。

  1. {$substr” : [expr, startOffset, numToReturn]}
    在那之中第二个参数expr必得是个字符串,这一个操作会截取这一个字符串的子串(从第startOffset字节起来的numToReturn字节,注意,是字节,不是字符。在多字节编码中进一层要精心那或多或少)expr必得是字符串。
  2. {“$concat” : [expr1[, expr2, …, exprN]]}
    将加以的表明式(可能字符串)连接在一块作为重回结果。
  3. {“$toLower” : expr}
    参数expr必须是个字符串值,这么些操作再次来到expr的小写情势。
  4. {“$toUpper” : expr}
    参数expr必得是个字符串值,那么些操作再次回到expr的大写格局。
  • 逻辑表明式

适用于单个文书档案的演算,通过这几个操作符,就足以在集合中运用更复杂的逻辑,能够对两样数额实践不黄金年代的代码,得到不相同的结果。

  1. {$cmp” : [expr1, expr2]}
    相比expr1和expr2。假使expr1等于expr2,重临0;如若expr1 <
    expr2,再次来到叁个负数;借使expr1 > expr2,再次回到一个正数。
  2. {“$strcasecmp” : [string1, string2]}
    比较string1和string2,区分朗朗上口写。只对 ASCII 组成的字符串有效。
  3. {“$eq”/”$ne”/”$gt”/”$gte”/”$lt”/”$lte” : [expr1, expr2]}
    对expr1和expr2推行相应的比较操作,重返相比较的结果(true或false)。
  4. {“$and” : [expr1[, expr2, …, exprN]]}
    假设拥有表明式的值都以true,那就再次回到true,不然再次回到false。
  5. {“$or” : [expr1[, expr2, …, exprN]]}
    只要有自由表达式的值为true,就回到true,不然重返false。
  6. {“$not” : expr} 对expr取反。
  7. {“$cond” : [booleanExpr, trueExpr, falseExpr]}
    假诺booleanExpr的值是true,那就赶回trueExpr,不然再次回到falseExpr。
  8. {“$ifNull” : [expr, replacementExpr]}
    假如expr是null,重临replacementExpr,不然重临expr。
  • 日期表明式

适用于单个文书档案的演算,只好对日期类型的字段举行日期操作,不可能对非日期类型字段做日期操作。

  1. {$year: “$date” } 再次来到日期的年份部分
  2. {$month: “$date” } 重回日期的月份部分
  3. {$dayOfMonth: “$date” } 再次来到日期的天部分
  4. {$hour: “$date” } 重回日期的钟点有些
  5. {$minute: “$date” } 再次回到日期的分钟部分
  6. {$second: “$date” } 重返日期的秒部分
  7. {$millisecond: “$date” } 重临日期的微秒部分
  8. {$dayOfYear: “$date” } 一年中的第几天
  9. {$dayOfWeek: “$date” } 16日中的第几天,between 1 (Sunday卡塔尔国 and 7
    (Saturday卡塔尔(英语:State of Qatar).
  10. {$week: “$date” }
    以0到53之内的数字再次来到一年中国和东瀛期的周数。周从星期六初叶,第14日从一年中的第八个周末初阶。一年中首先个周天在此之前的光阴是在第0周。

可参考:https://docs.mongodb.com/manual/reference/operator/aggregation/

四、结语

 
  应该尽或许在管道的始发阶段(试行”$project”、”$group”或然”$unwind”操作以前)就将尽或者多的文书档案和字段过滤掉。管道假使不是直接从原先的集纳中央银行使数据,那就不可能在挑选和排序中动用索引。借使大概,聚合管道会尝试对操作进行排序,以便能够行得通接收索引。

   
MongoDB不许单风流浪漫的集纳操作占用过多的系列内部存储器:假设MongoDB开采有个别聚合操作占用了百分之七十五上述的内部存款和储蓄器,那些操作就能够平昔出口错误。允许将出口结果使用管道归入二个聚聚集是为了有助于以往采用(那样能够将所需的内部存款和储蓄器减至最小)。

   
那篇文章首要摘录自《MongoDB权威指南第二版》,Mongo类别的尾声风度翩翩篇文章了,近些日子学MongoDB学得头都有一点大了,希图换个样子学学了…共勉!

Leave a Comment.