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

Gruppieren von Dokumenten in Paaren mit Mongo-Aggregation

Dies ist mit dem Aggregations-Framework einfach nicht möglich, und die einzige aktuelle MongoDB-Methode, die für diese Art von Operation verfügbar ist, ist mapReduce.

Der Grund dafür ist, dass ein Aggregationsrahmen keine Möglichkeit hat, auf irgendein anderes Dokument in der Pipeline als das vorliegende zu verweisen. Dies gilt tatsächlich auch für das „Gruppieren“ von Pipeline-Stufen, denn obwohl Dinge auf einem „Schlüssel“ gruppiert sind, können Sie einzelne Dokumente nicht wirklich so behandeln, wie Sie es möchten.

MapReduce hingegen verfügt über eine Funktion, mit der Sie hier tun können, was Sie möchten, und die nicht einmal "direkt" mit der Aggregation zusammenhängt. Es ist in der Tat die Fähigkeit, über alle Phasen hinweg "Variablen mit globalem Geltungsbereich" zu haben. Und eine "Variable", um im Grunde "das letzte Dokument zu speichern", ist alles, was Sie brauchen, um Ihr Ergebnis zu erzielen.

Es ist also ein ganz einfacher Code, und es ist tatsächlich keine "Reduktion" erforderlich:

db.collection.mapReduce(
    function () {
      if (lastVal != null)
        emit( this._id, this.val - lastVal );
      lastVal = this.val;
    },
    function() {}, // mapper is not called
    {
        "scope": { "lastVal": null },
        "out": { "inline": 1 }
    }
)

Das gibt Ihnen ein ähnliches Ergebnis:

{
    "results" : [
            {
                    "_id" : ObjectId("54a425a99b8bcd6f73e2d662"),
                    "value" : 2
            },
            {
                    "_id" : ObjectId("54a425a99b8bcd6f73e2d663"),
                    "value" : 3
            },
            {
                    "_id" : ObjectId("54a425a99b8bcd6f73e2d664"),
                    "value" : 4
            }
    ],
    "timeMillis" : 3,
    "counts" : {
            "input" : 4,
            "emit" : 3,
            "reduce" : 0,
            "output" : 3
    },
    "ok" : 1
}

Das ist wirklich nur die Auswahl von "etwas Einzigartigem" als ausgegebene _id Wert und nicht irgendetwas Spezifisches, denn alles, was dies wirklich tut, ist der Unterschied zwischen Werten in unterschiedlichen Dokumenten.

Globale Variablen sind normalerweise die Lösung für diese Art von "Paar"-Aggregationen oder das Erzeugen von "laufenden Summen". Im Moment hat das Aggregations-Framework keinen Zugriff auf globale Variablen, auch wenn es durchaus wünschenswert wäre, dies zu haben. Das mapReduce-Framework hat sie, also ist es wahrscheinlich fair zu sagen, dass sie auch für das Aggregation-Framework verfügbar sein sollten.

Im Moment sind sie es aber nicht, also bleib bei mapReduce.