Този въпрос изглежда идва много пъти без решение. Има две възможни решения, които знам:решение 1 - използване на mapReduce. mapReduce е общата форма на агрегиране, която позволява на потребителя да прави всичко, което може да се въобрази и програмируемо.
Следното е решението на mongo shell, използващо mapReduce. Разглеждаме следната колекция 'st'.
{ "_id" : ObjectId("51d6d23b945770d6de5883f1"), "foo" : "foo1", "bar" : "bar1" }
{ "_id" : ObjectId("51d6d249945770d6de5883f2"), "foo" : "foo2", "bar" : "bar2" }
{ "_id" : ObjectId("51d6d25d945770d6de5883f3"), "foo" : "foo2", "bar" : "bar22" }
{ "_id" : ObjectId("51d6d28b945770d6de5883f4"), "foo" : "foo2", "bar" : "bar3" }
{ "_id" : ObjectId("51d6daf6945770d6de5883f5"), "foo" : "foo3", "bar" : "bar3" }
{ "_id" : ObjectId("51d6db03945770d6de5883f6"), "foo" : "foo4", "bar" : "bar24" }
искаме да групираме по foo и за всяко foo да преброим броя на документи, както и броя на документи с лента, съдържаща подниза 'bar2'. това е:
foo1: nbdoc=1, n_match = 0
foo2: nbdoc=3, n_match = 2
foo3: nbdoc=1, n_match = 0
foo4: nbdoc=1, n_match = 1
За да направите това, дефинирайте следната функция за карта
var mapFunction = function() {
var key = this.foo;
var nb_match_bar2 = 0;
if( this.bar.match(/bar2/g) ){
nb_match_bar2 = 1;
}
var value = {
count: 1,
nb_match: nb_match_bar2
};
emit( key, value );
};
и следната функция за намаляване
var reduceFunction = function(key, values) {
var reducedObject = {
count: 0,
nb_match:0
};
values.forEach( function(value) {
reducedObject.count += value.count;
reducedObject.nb_match += value.nb_match;
}
);
return reducedObject;
};
стартирайте mapduce и съхранете резултата в колекцията map_reduce_result
db.st.mapReduce(mapFunction, reduceFunction, {out:'map_reduce_result'})
{
"result" : "map_reduce_result",
"timeMillis" : 7,
"counts" : {
"input" : 6,
"emit" : 6,
"reduce" : 1,
"output" : 4
},
"ok" : 1,
}
И накрая, можем да отправим запитване към колекцията map_reduce_result, готово! решението
> db.map_reduce_result.find()
{ "_id" : "foo1", "value" : { "count" : 1, "nb_match" : 0 } }
{ "_id" : "foo2", "value" : { "count" : 3, "nb_match" : 2 } }
{ "_id" : "foo3", "value" : { "count" : 1, "nb_match" : 0 } }
{ "_id" : "foo4", "value" : { "count" : 1, "nb_match" : 1 } }
решение 2- използване на две отделни агрегации и сливане. Няма да давам подробности за това решение, тъй като всеки потребител на mongo може лесно да го направи. стъпка 1:направете агрегацията, като игнорирате частта, която изисква regex за сумиране. стъпка 2:направете второ групиране на агрегации на същия ключ като този от първа стъпка.етап 1 на тръбопровода:съответства на регулярния израз;етап 2:групирайте на същия ключ като в първата стъпка и пребройте броя документи във всяка група {$sum:1};стъпка 3:обединете резултата от стъпка 1 и 2:за всеки ключ, който се появява и в двата резултата, добавете новото поле, ако ключът не присъства във втория резултат, задайте новия ключ на 0.
Ето! друго решение.