2016-06-21 4 views
1

Например, я следующая коллекция:Получить счетчик "LOGLEVEL" для каждого "имя"

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}}}} 
    }} 
) 

ответ

3

Удалите { "$sum": 1 } и { "$sum": 0 } выражения в ваших if/else условных блоков, заменить их со значениями 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 
} 
+0

Хороший вопрос о том, если/else блоки, но все же я ищу DRY-решение (не дублируйте блок loglevel) – madzohan

+0

@madzohan Обновлен мой ответ, чтобы включить DRY-подход. – chridam

+0

приятно! также не могли бы вы сказать, какой путь будет лучше (производительность и т. д.) - сохранить логику как группировку в mongodb или переместить ее на язык программирования, такой как python? – madzohan

1

Если я правильно понимаю, вы хотите сумму logle vels против каждого имени. не должно это помочь?

db.names.aggregate([{$group:{_id:{name:"$name",loglevel:"$loglevel"},sum:{$sum:1}}}]) 
+0

yep Я пробовал это раньше, но мне это нужно сгруппированным способом '$ name' со всеми loglevels, аннотированными – madzohan

+0

справа. просто увидел ответ @ Chridam. думаю, это то, что вы ищете. – KaSh

Смежные вопросы