Mongodb聚合,如何按间隔标准计算文件?

LeM*_*sel 2 mongodb aggregation-framework

我的MongoDB文档如下所示:

{StatCode : "...", LoadTime  : "..."}
Run Code Online (Sandbox Code Playgroud)

例如,数据可能如下所示:

+-----+----------+------------+
| _id | StatCode |  LoadTime  |
+-----+----------+------------+
|   1 |      200 |      0,345 |
|   2 |      200 |      0,234 |
|   3 |      200 |      0,396 |
|   4 |      200 |      1,234 |
|   5 |      200 |      2,564 |
|   6 |      200 |      0,437 |
|   7 |      301 |      0,523 |
|   8 |      301 |      0,628 |
|   9 |      301 |      0,712 |
|  10 |      200 |      1,784 | 
+-----+----------+------------+
Run Code Online (Sandbox Code Playgroud)

我希望通过LoadTime值得到计数组,如下所示:最慢(超过2),慢(1到2之间),中(0到1之间)和快(低于0.5)

使用Data示例,结果如下所示:

+----------+-------+
| Info_id  | Count |
+----------+-------+
| Slowest  |     1 |
| Slow     |     2 |
| Medium   |     3 |
| Fast     |     4 |
+----------+-------+
Run Code Online (Sandbox Code Playgroud)

编辑:备注Neil Lunn,来自MongoDB的示例文档

{
    "_id" : 1,
    "LoadTime" : NumberLong(345),
    "StatCode" : 200
}
{
    "_id" : 2,
    "LoadTime" : NumberLong(234),
    "StatCode" : 200
}
....
{
    "_id" : 9,
    "LoadTime" : NumberLong(712),
    "StatCode" : 301
}
{
    "_id" : 10,
    "LoadTime" : NumberLong( 1784),
    "StatCode" : 200
}
Run Code Online (Sandbox Code Playgroud)

如何使用MongoDB聚合框架实现此目的?

Nei*_*unn 5

你想要的是$ cond运算符和$和.的相当多的嵌套条件.但这应该给你你想要的.

db.collection.aggregate([
    {"$group": {
      "_id": {"$cond": [
          {"$gte": ["$LoadTime", 2000] },
          "Slowest",                                   // return "Slowest" where true
          {"$cond": [
              {"$and": [
                  {"$lt": ["$LoadTime", 2000] },
                  {"$gte": ["$LoadTime", 1000] }
              ]},
              "Slow",                                  // then "Slow" here where true
              {"$cond": [
                  {"$and": [
                      {"$lt": ["$LoadTime", 1000] },
                      {"$gte": ["$LoadTime", 500 ] }
                  ]},
                  "Medium",                            // then "Medium" where true
                  "Fast"                               // and finally "Fast" < 500
              ]}
          ]}
      ]},
      "count": {"$sum": 1}
    }},
    {"$sort": { "count": 1 }}
])
Run Code Online (Sandbox Code Playgroud)

由于你的时间是整整几毫秒,你可以看到我要求编辑的原因.

因为$ cond是一个三元运算符,它需要三个参数:

  • 评估哪个条件返回布尔值
  • 条件为真的返回值
  • 条件为false的返回值

因此,我们的想法是,您将整个条件嵌套,在false上移动到下一个测试,直到找到要匹配的条件,并返回一个值.

$和部分是一个排列条件包括.这为您提供了范围.所以在最长的部分:

          {"$cond": [                             // Evaluate here
              {"$and": [                          // Within the range of the next 2
                  {"$lt": ["$LoadTime", 2000] },
                  {"$gte": ["$LoadTime", 1000] }
              ]},
              "Slow",                            // true condition - return
              {"$cond": [                        // false - move to next eval
Run Code Online (Sandbox Code Playgroud)

通过你的级联留下"快速" times500毫秒.

每个都keys被发送到组,我们只是{ $sum: 1 }为了得到一个计数,因为它们被组合在一起.

如果您需要在自己的语言实现中,整个pipeline内容

aggregate(..)

只是JSON,所以你可以将它解析为你的原生数据结构,如果手工翻译让你恍惚,或者像我一样你只是懒惰.

编辑

由于评论,似乎有必要解释所提出的查询的形式.所以这里是编辑附录以供澄清.

学习使用聚合管道时,以及写出和测试复杂的一系列阶段或逻辑的良好实践时,我发现通过一步一步地实现部件来可视化结果是有用的.因此,在写这样的事情我的情况下,第一个步骤是如下:

db.collection.aggregate([
    {"$group": {
      "_id": {"$cond": [
          {"$gte": ["$LoadTime", 2000] },
          "Slowest",
          null
       ]}
    }}
])
Run Code Online (Sandbox Code Playgroud)

现在,这将让我的"最慢"为我所期望的计数,然后别的一切都成null.所以到目前为止我有一个阶段可以看到结果.但是在测试时,我会在继续构建链之前实际执行类似的操作:

db.collection.aggregate([
    {"$group": {
      "_id": {"$cond": [
          {"$and": [
              {"$lt": ["$LoadTime", 2000] },
              {"$gte": ["$LoadTime", 1000] }
          ]},
          "Slow",
          null
      ]}
    }}
])
Run Code Online (Sandbox Code Playgroud)

所以我只是将"慢"(2000到1000 之间)的结果与null桶中的其他所有内容相比较.所以我的总体数量保持不变.

最后的查询中,正如所指出的那样,在嵌套的三元条件中,第一阶段已经评估false下一个运算符正在测试的项目.这意味着它们 大于第一阶段已经测试过的值,并且不需要测试该条件,因此可以写成如下:

db.collection.aggregate([
    {"$group": {
      "_id": {"$cond": [
          {"$gte": ["$LoadTime", 2000] },       // Caught everything over 2000
          "Slowest",
          {"$cond": [
              {"$gte": ["$LoadTime", 1000] }    // Catch things still over 1000
              "Slow",
              {"$cond": [                       // Things under 1000 go here

              // and so on
Run Code Online (Sandbox Code Playgroud)

短路,因为没有评价真正需要测试的东西,不会通过走到下一个逻辑条件.

因此,纯粹出于视觉原因以及剪切和粘贴逻辑的纯粹懒惰,我们最终使用$和条件来扩展形式来包装范围.但是,对于那些不使用的的使用三元形式有一个清晰的视觉线索,结果在这个阶段被匹配将下降之间的价值观2000ms1000ms,等等,这是您要在每个范围的结果是什么.

正如我所说的,不必要有因为逻辑是如何工作的,但它一个发展阶段,并明确对谁尚未人们避开他们头上的的使用三元形式$ COND提供.