Deze vraag lijkt vaak zonder oplossing te komen. Er zijn twee mogelijke oplossingen die ik ken:oplossing 1- met behulp van mapReduce. mapReduce is de algemene vorm van aggregatie waarmee de gebruiker alles kan doen wat denkbaar en programmeerbaar is.
hierna volgt de mongo-shell-oplossing die mapReduce gebruikt. We beschouwen de volgende 'st'-verzameling.
{ "_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" }
we willen groeperen op foo, en voor elke foo, tel het aantal doc, evenals het aantal doc met balk met de substring 'bar2'.dat is:
foo1: nbdoc=1, n_match = 0
foo2: nbdoc=3, n_match = 2
foo3: nbdoc=1, n_match = 0
foo4: nbdoc=1, n_match = 1
Om dat te doen, definieert u de volgende kaartfunctie
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 );
};
en de volgende reduceerfunctie
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;
};
voer mapduce uit en sla het resultaat op in de verzameling 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,
}
Ten slotte kunnen we de verzameling map_reduce_result opvragen, voila! de oplossing
> 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 } }
oplossing 2 - twee afzonderlijke aggregaties gebruiken en samenvoegen Ik zal geen details geven voor deze oplossing omdat elke mongo-gebruiker het gemakkelijk kan doen. stap 1:doe de aggregatie en negeer het deel dat regex vereist om op te tellen. stap 2:doe een tweede aggregatiegroepering op dezelfde sleutel als die van stap één.fase 1 van de pijplijn:match de reguliere expressie;fase 2:groepeer op dezelfde sleutel als in de eerste stap en tel het aantal documenten in elke groep {$sum:1};stap 3:voeg het resultaat van stap 1 en 2 samen:voor elke sleutel die in beide resultaten verschijnt, voeg het nieuwe veld toe, als de sleutel niet aanwezig is in het tweede resultaat, zet de nieuwe sleutel dan op 0.
Voila! een andere oplossing.