Questo è qualcosa che semplicemente non può essere fatto con il framework di aggregazione e l'unico metodo MongoDB attualmente disponibile per questo tipo di operazione è mapReduce.
Il motivo è che il quadro di aggregazione non ha modo di fare riferimento a nessun altro documento in cantiere rispetto a quello attuale. Questo vale anche per le fasi di "raggruppamento" della pipeline, poiché anche se le cose sono raggruppate su una "chiave" non puoi davvero gestire i singoli documenti nel modo desiderato.
MapReduce d'altra parte ha una funzionalità disponibile che ti consente di fare ciò che vuoi qui e non è nemmeno "direttamente" correlata all'aggregazione. In effetti, è la capacità di avere "variabili con ambito globale" in tutte le fasi. E avere una "variabile" per "memorizzare l'ultimo documento" è tutto ciò che ti serve per ottenere il tuo risultato.
Quindi è un codice abbastanza semplice e in effetti non è richiesta alcuna "riduzione":
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 }
}
)
Il che ti dà un risultato molto simile a questo:
{
"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
}
In realtà è solo selezionare "qualcosa di unico" come _id
emesso valore piuttosto che qualcosa di specifico, perché tutto ciò che sta facendo è davvero la differenza tra valori su documenti diversi.
Le variabili globali sono solitamente la soluzione a questi tipi di aggregazioni di "abbinamento" o di produzione di "totali correnti". In questo momento il framework di aggregazione non ha accesso alle variabili globali, anche se potrebbe essere bello averlo. Il framework mapReduce li ha, quindi è probabilmente corretto dire che dovrebbero essere disponibili anche per il framework di aggregazione.
Al momento non lo sono, quindi resta con mapReduce.