获取 “记录水平” 的计数每个 “名”
问题描述:
,比如我有以下集合:获取 “记录水平” 的计数每个 “名”
db.names.find({})
{ "_id" : ObjectId("5768d9b4bc6f464899594570"), "name" : "t1", "loglevel" : "ERROR" }
{ "_id" : ObjectId("5768d9d5bc6f464899594571"), "name" : "t1", "loglevel" : "ERROR" }
{ "_id" : ObjectId("5768d9dcbc6f464899594572"), "name" : "t1", "loglevel" : "WARNING" }
{ "_id" : ObjectId("5768d9dfbc6f464899594573"), "name" : "t1", "loglevel" : "WARNING" }
{ "_id" : ObjectId("5768d9e0bc6f464899594574"), "name" : "t1", "loglevel" : "WARNING" }
{ "_id" : ObjectId("5768d9e7bc6f464899594575"), "name" : "t1", "loglevel" : "INFO" }
{ "_id" : ObjectId("5768d9f3bc6f464899594576"), "name" : "t2", "loglevel" : "INFO" }
{ "_id" : ObjectId("5768d9f9bc6f464899594577"), "name" : "t2", "loglevel" : "ERROR" }
{ "_id" : ObjectId("5768da19bc6f464899594578"), "name" : "t2", "loglevel" : "ERROR" }
{ "_id" : ObjectId("5768da1abc6f464899594579"), "name" : "t2", "loglevel" : "ERROR" }
{ "_id" : ObjectId("5768da1bbc6f46489959457a"), "name" : "t2", "loglevel" : "ERROR" }
{ "_id" : ObjectId("5768e247bc6f46489959457b"), "name" : "t3", "loglevel" : "INFO" }
我都试过,但我认为它应该是更好的解决方案(也可以省略else
)
db.names.aggregate(
{$group: {
_id: "$name",
error: {$sum: {$cond: {if: {$eq: ['$loglevel', 'ERROR']}, then: {$sum: 1}, else: {$sum: 0}}}},
warning: {$sum: {$cond: {if: {$eq: ['$loglevel', 'WARNING']}, then: {$sum: 1}, else: {$sum: 0}}}},
info: {$sum: {$cond: {if: {$eq: ['$loglevel', 'INFO']}, then: {$sum: 1}, else: {$sum: 0}}}}
}}
)
答
在if/else
条件块取下{ "$sum": 1 }
和{ "$sum": 0 }
表达式(分别为每个条件块)与值1和0代替它们。
最后的管道应该是这样的,使用其他$cond
语法,省略了if/else
块:
db.names.aggregate([
{
"$group": {
"_id": "$name",
"error": {
"$sum": {
"$cond": [ { "$eq": [ "$loglevel", "ERROR" ] }, 1, 0]
}
},
"warning":{
"$sum": {
"$cond": [ { "$eq": [ "$loglevel", "WARNING" ] }, 1, 0 ]
}
},
"info": {
"$sum": {
"$cond": [ { "$eq": [ "$loglevel", "INFO" ] }, 1, 0 ]
}
}
}
}
])
或动态创建的管道,由于可能的状态数组:
var statuses = ["ERROR", "WARNING", "INFO"],
groupOperator = { "$group": { "_id": "$name" } };
statuses.forEach(function (status){
groupOperator["$group"][status.toLowerCase()] = {
"$sum": {
"$cond": [ { "$eq": [ "$loglevel", status ] }, 1, 0]
}
}
});
db.names.aggregate([groupOperator]);
输出
/* 1 */
{
"_id" : "t1",
"error" : 2,
"warning" : 3,
"info" : 1
}
/* 2 */
{
"_id" : "t2",
"error" : 4,
"warning" : 0,
"info" : 1
}
/* 3 */
{
"_id" : "t3",
"error" : 0,
"warning" : 0,
"info" : 1
}
关于if/else块的好处,但仍然在寻找DRY解决方案(不要复制loglevel的块) – madzohan
@madzohan更新我的答案以包含DRY方法。 – chridam
不错!你也可以告诉我哪种方式会更好(性能等) - 保持像mongodb中的分组逻辑或将其移动到编程语言,如Python? – madzohan