Isso é algo que simplesmente não pode ser feito com a estrutura de agregação, e o único método atual do MongoDB disponível para esse tipo de operação é mapReduce.
A razão é que a estrutura de agregação não tem como se referir a nenhum outro documento em andamento além do presente. Na verdade, isso também se aplica aos estágios de pipeline de "agrupamento", pois mesmo que as coisas estejam agrupadas em uma "chave", você não pode realmente lidar com documentos individuais da maneira que deseja.
O MapReduce, por outro lado, tem um recurso disponível que permite que você faça o que quiser aqui, e não está nem "diretamente" relacionado à agregação. Na verdade, é a capacidade de ter "variáveis de escopo global" em todos os estágios. E ter uma "variável" para basicamente "armazenar o último documento" é tudo o que você precisa para alcançar seu resultado.
Portanto, é um código bastante simples e, de fato, não há "redução" necessária:
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 }
}
)
O que lhe dá um resultado muito parecido com este:
{
"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
}
Isso é apenas escolher "algo único" como o
_id
emitido valor em vez de qualquer coisa específica, porque tudo isso está realmente fazendo é a diferença entre valores em documentos diferentes. As variáveis globais geralmente são a solução para esses tipos de agregações de "emparelhamento" ou produção de "totais em execução". No momento, a estrutura de agregação não tem acesso a variáveis globais, embora possa ser bom ter isso. A estrutura mapReduce as possui, portanto, provavelmente é justo dizer que elas também devem estar disponíveis para a estrutura de agregação.
No momento eles não são, então fique com mapReduce.