我的MongoDB文档如下所示:
{StatCode : "...", LoadTime : "..."}
例如,数据可能如下所示:
+-----+----------+------------+
| _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 |
+-----+----------+------------+
我希望通过LoadTime值获取计数组,如下所示: 最慢(超过2),慢(1和2之间),中(低于0.5和1)和快(低于0.5)
使用Data示例,结果如下所示:
+----------+-------+
| Info_id | Count |
+----------+-------+
| Slowest | 1 |
| Slow | 2 |
| Medium | 3 |
| Fast | 4 |
+----------+-------+
编辑:备注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
}
如何使用MongoDB聚合框架实现此目的?
答案 0 :(得分:5)
您需要的是$cond运算符以及$and的多个嵌套条件。但这应该可以满足您的需求。
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 }}
])
由于您的时间整个毫秒,您可以看到我要求编辑的原因。
因为 $ cond 是一个ternary运算符,它需要三个参数:
因此,我们的想法是你嵌套整个条件,转到 false 上的 next 测试,直到找到匹配的条件,以及要返回的值。
$和部分是要包含的条件的数组。这为您提供了范围。所以在最长的部分:
{"$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
在{500}的情况下,times
为“快速”留下了“快速”。
这些keys
中的每一个都会发送到该组,我们只需{ $sum: 1 }
即可将它们组合在一起进行计数。
如果您需要在自己的语言实现中使用
中的整个pipeline
内容
aggregate(..)
只是JSON,所以你可以将它解析为你的原生数据结构,如果手工翻译让你失望,或者像我这样只是懒惰。
由于评论,似乎有必要解释所提出查询的表单。所以这里是编辑附录以供澄清。
当学习使用聚合管道,并且确实良好实践用于写出和测试一系列复杂的阶段或逻辑时,我通过一次执行一部分来发现可视化结果非常有用。因此,在编写此类内容的情况下,我的第一个步骤如下:
db.collection.aggregate([
{"$group": {
"_id": {"$cond": [
{"$gte": ["$LoadTime", 2000] },
"Slowest",
null
]}
}}
])
现在,这会让我按照我的预期计算“最慢”,然后将其他所有内容转移到null
。所以到目前为止我有一个阶段可以看到结果。但是当测试时,我会在继续构建链之前实际做这样的事情:
db.collection.aggregate([
{"$group": {
"_id": {"$cond": [
{"$and": [
{"$lt": ["$LoadTime", 2000] },
{"$gte": ["$LoadTime", 1000] }
]},
"Slow",
null
]}
}}
])
所以我只是将“慢”(在 2000和1000之间)的结果与null
桶中的其他所有内容相比较。所以我的总体数量保持不变。
在最终查询中,正如所指出的那样,在嵌套的ternary条件中,第一个阶段已经已经 评估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
短路评估,因为没有真实需要测试那些无法通过下一个逻辑条件的事情。
纯粹 视觉原因以及剪切和粘贴逻辑的纯粹懒惰,我们最终使用 $和条件换行范围。但是对于那些不习惯 ternary形式的使用,有一个清晰的视觉提示,在这个阶段匹配的结果将落在 2000ms
和1000ms
的值,依此类推,这就是您希望在每个范围内获得的结果。
正如我所说,由于逻辑的工作方式不必要,但 是一个开发阶段,并且清晰给尚未的人>了解使用 $ cond 提供的ternary表单。