C'est quelque chose qui ne peut tout simplement pas être fait avec le framework d'agrégation, et la seule méthode MongoDB actuellement disponible pour ce type d'opération est mapReduce.
La raison en est que le cadre d'agrégation n'a aucun moyen de se référer à un autre document dans le pipeline que celui-ci. Cela s'applique également aux étapes de "regroupement" du pipeline, car même si les éléments sont regroupés sur une "clé", vous ne pouvez pas vraiment traiter les documents individuels comme vous le souhaitez.
MapReduce, d'autre part, a une fonctionnalité disponible qui vous permet de faire ce que vous voulez ici, et ce n'est même pas "directement" lié à l'agrégation. Il s'agit en fait de la possibilité d'avoir des "variables de portée globale" à toutes les étapes. Et avoir une "variable" pour essentiellement "stocker le dernier document" est tout ce dont vous avez besoin pour obtenir votre résultat.
C'est donc un code assez simple, et il n'y a en fait aucune "réduction" nécessaire :
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 }
}
)
Ce qui vous donne un résultat semblable à celui-ci :
{
"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
}
C'est vraiment juste choisir "quelque chose d'unique" comme _id
émis valeur plutôt que quelque chose de spécifique, car tout ce que cela fait vraiment est la différence entre les valeurs sur des documents différents.
Les variables globales sont généralement la solution à ces types d'agrégations "d'appariement" ou produisant des "totaux cumulés". À l'heure actuelle, le cadre d'agrégation n'a pas accès aux variables globales, même si cela pourrait bien être une bonne chose à avoir. Le framework mapReduce les a, il est donc probablement juste de dire qu'ils devraient également être disponibles pour le framework d'agrégation.
Pour le moment, ils ne le sont pas, alors restez avec mapReduce.