Vous ne pouvez pas encore le faire en utilisant le cadre d'agrégation - vous pouvez obtenir la valeur $max ou la valeur de date maximale pour chaque groupe, mais le cadre d'agrégation n'a pas encore de moyen d'accumuler le top N et il n'y a aucun moyen de pousser le document entier dans l'ensemble de résultats (uniquement les champs individuels).
Il faut donc se rabattre sur MapReduce. Voici quelque chose qui fonctionnerait, mais je suis sûr qu'il existe de nombreuses variantes (toutes nécessitent en quelque sorte de trier un tableau d'objets en fonction d'un attribut spécifique, j'ai emprunté ma solution à l'un des les réponses à cette question .
Fonction Map - génère le nom du groupe en tant que clé et tout le reste du document en tant que valeur - mais elle le génère en tant que document contenant un tableau car nous essaierons d'accumuler un tableau de résultats par groupe :
map = function () {
emit(this.name, {a:[this]});
}
La fonction reduce accumulera tous les documents appartenant au même groupe dans un tableau (via concat). Notez que si vous optimisez reduce pour ne conserver que les cinq premiers éléments du tableau en vérifiant la date, vous n'aurez pas besoin de la fonction finalize et vous utiliserez moins de mémoire lors de l'exécution de mapreduce (ce sera également plus rapide).
reduce = function (key, values) {
result={a:[]};
values.forEach( function(v) {
result.a = v.a.concat(result.a);
} );
return result;
}
Étant donné que je conserve toutes les valeurs pour chaque clé, j'ai besoin d'une fonction de finalisation pour extraire uniquement les cinq derniers éléments par clé.
final = function (key, value) {
Array.prototype.sortByProp = function(p){
return this.sort(function(a,b){
return (a[p] < b[p]) ? 1 : (a[p] > b[p]) ? -1 : 0;
});
}
value.a.sortByProp('date');
return value.a.slice(0,5);
}
En utilisant un modèle de document similaire à celui que vous avez fourni, vous l'exécutez en appelant la commande mapReduce :
> db.top5.mapReduce(map, reduce, {finalize:final, out:{inline:1}})
{
"results" : [
{
"_id" : "group1",
"value" : [
{
"_id" : ObjectId("516f011fbfd3e39f184cfe13"),
"name" : "group1",
"date" : ISODate("2013-04-17T20:07:59.498Z"),
"contents" : 0.23778377776034176
},
{
"_id" : ObjectId("516f011fbfd3e39f184cfe0e"),
"name" : "group1",
"date" : ISODate("2013-04-17T20:07:59.467Z"),
"contents" : 0.4434165076818317
},
{
"_id" : ObjectId("516f011fbfd3e39f184cfe09"),
"name" : "group1",
"date" : ISODate("2013-04-17T20:07:59.436Z"),
"contents" : 0.5935856597498059
},
{
"_id" : ObjectId("516f011fbfd3e39f184cfe04"),
"name" : "group1",
"date" : ISODate("2013-04-17T20:07:59.405Z"),
"contents" : 0.3912118375301361
},
{
"_id" : ObjectId("516f011fbfd3e39f184cfdff"),
"name" : "group1",
"date" : ISODate("2013-04-17T20:07:59.372Z"),
"contents" : 0.221651989268139
}
]
},
{
"_id" : "group2",
"value" : [
{
"_id" : ObjectId("516f011fbfd3e39f184cfe14"),
"name" : "group2",
"date" : ISODate("2013-04-17T20:07:59.504Z"),
"contents" : 0.019611883210018277
},
{
"_id" : ObjectId("516f011fbfd3e39f184cfe0f"),
"name" : "group2",
"date" : ISODate("2013-04-17T20:07:59.473Z"),
"contents" : 0.5670706110540777
},
{
"_id" : ObjectId("516f011fbfd3e39f184cfe0a"),
"name" : "group2",
"date" : ISODate("2013-04-17T20:07:59.442Z"),
"contents" : 0.893193120136857
},
{
"_id" : ObjectId("516f011fbfd3e39f184cfe05"),
"name" : "group2",
"date" : ISODate("2013-04-17T20:07:59.411Z"),
"contents" : 0.9496864483226091
},
{
"_id" : ObjectId("516f011fbfd3e39f184cfe00"),
"name" : "group2",
"date" : ISODate("2013-04-17T20:07:59.378Z"),
"contents" : 0.013748752186074853
}
]
},
{
"_id" : "group3",
...
}
]
}
],
"timeMillis" : 15,
"counts" : {
"input" : 80,
"emit" : 80,
"reduce" : 5,
"output" : 5
},
"ok" : 1,
}
Chaque résultat a _id comme nom de groupe et des valeurs comme tableau des cinq documents les plus récents de la collection pour ce nom de groupe.