Все още не можете да направите това с помощта на рамката за агрегиране - можете да получите стойността на $max или горната дата за всяка група, но рамката за агрегиране все още няма начин да натрупа най-високите N плюс няма начин да поставите целия документ в набора от резултати (само отделни полета).
Така че трябва да се върнете към MapReduce. Ето нещо, което би свършило работа, но съм сигурен, че има много варианти (всички изискват сортиране по някакъв начин на масив от обекти въз основа на конкретен атрибут, взех назаем моето решение от един от отговорите в този въпрос .
Функция Map - извежда името на групата като ключ и цялата останала част от документа като стойност - но го извежда като документ, съдържащ масив, защото ще се опитаме да натрупаме масив от резултати за група:
map = function () {
emit(this.name, {a:[this]});
}
Функцията за намаляване ще натрупа всички документи, принадлежащи към една и съща група, в един масив (чрез concat). Обърнете внимание, че ако оптимизирате намалението, за да запазите само първите пет елемента на масива чрез проверка на датата, тогава няма да имате нужда от функцията за финализиране и ще използвате по-малко памет по време на изпълнение на mapreduce (също така ще бъде по-бързо).
reduce = function (key, values) {
result={a:[]};
values.forEach( function(v) {
result.a = v.a.concat(result.a);
} );
return result;
}
Тъй като запазвам всички стойности за всеки ключ, имам нужда от функция за финализиране, за да извадя само последните пет елемента на ключ.
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);
}
Използвайки шаблонен документ, подобен на предоставения от вас, стартирате това, като извикате командата 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,
}
Всеки резултат има _id като име на група и стойности като масив от последните пет документа от колекцията за това име на група.