MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Wie kann ich mit mongodb eine Anzahl von Datensätzen pro einem bestimmten Feld auswählen?

Sie können dies noch nicht mit dem Aggregationsframework tun - Sie können den $max- oder Top-Datumswert für jede Gruppe abrufen, aber das Aggregationsframework hat noch keine Möglichkeit, Top N zu akkumulieren, und es gibt keine Möglichkeit, das gesamte Dokument in die Ergebnismenge zu verschieben (nur einzelne Felder).

Man muss also auf MapReduce zurückgreifen. Hier ist etwas, das funktionieren würde, aber ich bin mir sicher, dass es viele Varianten gibt (alle erfordern irgendwie das Sortieren eines Arrays von Objekten basierend auf einem bestimmten Attribut, ich habe meine Lösung von einem von die Antworten in dieser Frage .

Kartenfunktion - gibt den Gruppennamen als Schlüssel und den gesamten Rest des Dokuments als Wert aus - aber es gibt es als Dokument aus, das ein Array enthält, weil wir versuchen werden, ein Array von Ergebnissen pro Gruppe zu sammeln:

map = function () { 
    emit(this.name, {a:[this]}); 
}

Die Reduce-Funktion sammelt alle Dokumente, die zu derselben Gruppe gehören, in einem Array (über concat). Beachten Sie, dass Sie, wenn Sie Reduce so optimieren, dass nur die obersten fünf Array-Elemente beibehalten werden, indem Sie das Datum prüfen, die Finalize-Funktion nicht benötigen und weniger Speicher beim Ausführen von MapReduce verbrauchen (es wird auch schneller).

reduce = function (key, values) {
    result={a:[]};
    values.forEach( function(v) {
        result.a = v.a.concat(result.a);
    } );
    return result;
}

Da ich alle Werte für jeden Schlüssel behalte, brauche ich eine Finalize-Funktion, um nur die letzten fünf Elemente pro Schlüssel herauszuziehen.

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);
}

Unter Verwendung eines Vorlagendokuments, das dem von Ihnen bereitgestellten ähnlich ist, führen Sie dies aus, indem Sie den Befehl mapReduce aufrufen:

> 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,
}

Jedes Ergebnis hat _id als Gruppenname und Werte als Array der letzten fünf Dokumente aus der Sammlung für diesen Gruppennamen.