2013-07-17 4 views
1

Я пытаюсь объединить сотрудников, используя отдел и статус, для расчета суммы сумм для каждого состояния. Отсюда:MongoDB Aggregation Несколько ключей

{ 
    name : "Employee_1", 
    department: "hr", 
    status : "exist" 
}, 
{ 
    name : "Employee_2", 
    department: "acme", 
    status : "absent" 
}, 
{ 
    name : "Employee_3", 
    department: "acme", 
    status : "absent" 
} 
... 

к этому:

{ 
    department: "hr", 
    statuses: { 
    exist: 1, 
    absent: 0 
    } 
}, 
{ 
    department: "acme", 
    statuses: { 
    exist: 0, 
    absent: 2 
    } 
} 
... 

Я пытаюсь сделать это с помощью:

Employee.aggregate( 
     { $group: { 
      _id: '$department', 
      statuses: { $addToSet: "$status" } 
     }}, 
     { $project: { _id: 1, statuses: 1 }}, 
     function(err, summary) { 
      console.log(summary); 
     } 
    ); 

я получаю только статусы в массиве производства "$ addToSet":

{ 
    department: "hr", 
    statuses: [ 
     'exist', 
     'absent' 
    ] 
}, 
{ 
    department: "acme", 
    statuses: [ 
     'exist', 
     'absent' 
    ] 
} 
... 

Как правильно поставить «{$ sum: 1}» для каждой из ста tuses? Спасибо за ответ.

ответ

1

Если возможный статус существует и отсутствует, вы можете использовать оператор $cond в сочетании с оператором $eq.

{ 
    $group : { 
     _id : '$department', 
     exist : { $sum : { $cond : [ { $eq : ['$status', 'exist'] } ,1,0 ] } }, 
     absent : { $sum : { $cond : [ { $eq : ['$status', 'absent'] } ,1,0 ] } } 
    } 
} 

После группировки, вы можете проецировать как вы хотите

1

mapReduce может использоваться для решения проблемы.

1) определим следующую функцию карту

var mapFunction = function() { 
    var key = this.department; 
    var nb_match_bar2 = 0; 
    var status_exist = 0; 
    var status_absent = 0; 
    if(this.status=="exist"){ 
    status_exist = 1; 
    }else{ 
    status_absent= 1; 
    } 
    var value = { 
    department: this.department, 
    statuses:{ 
     exist: status_exist, 
     absent: status_absent 
    } 
    }; 

    emit(key, value); 
}; 

2) определить функцию уменьшения

var reduceFunction = function(key, values) { 

    var reducedObject = { 
    department: key, 
    statuses: { 
     exist: 0, 
     absent:0 
    } 
    }; 
    values.forEach(function(value) { 
    reducedObject.statuses.exist += value.statuses.exist; 
    reducedObject.statuses.absent += value.statuses.absent; 
    } 
); 
    return reducedObject; 
}; 

3) запустить mapduce и сохранить результат в коллекции map_reduce_result

db.rien.mapReduce(mapFunction, reduceFunction, {out:'map_reduce_result'}) 

4), наконец, запрос коллекции map_reduce_result

db.map_reduce_result.find() 

Для вашей коллекции, это должно дать что-то вроде этого

{ 
    "_id" : "acme", 
    "value" : { 
     "department" : "acme", 
     "statuses" : { 
     "exist" : 0, 
     "absent" : 2 
     } 
    } 
} 
{ 
    "_id" : "hr", 
    "value" : { 
     "department" : "hr", 
     "statuses" : { 
     "exist" : 1, 
     "absent" : 0 
     } 
    } 
} 

, что вы можете легко настроить.

Надеюсь, это поможет.