sql >> Base de Datos >  >> NoSQL >> MongoDB

Agrupar documentos en pares usando la agregación mongo

Esto es algo que simplemente no se puede hacer con el marco de agregación, y el único método actual de MongoDB disponible para este tipo de operación es mapReduce.

El motivo es que un marco de agregación no tiene forma de hacer referencia a ningún otro documento en trámite que no sea el presente. En realidad, esto también se aplica a las etapas de canalización de "agrupación", ya que aunque las cosas se agrupan en una "clave", realmente no puede tratar con documentos individuales de la manera que desea.

MapReduce, por otro lado, tiene una función disponible que le permite hacer lo que quiera aquí, y ni siquiera está "directamente" relacionada con la agregación. De hecho, es la capacidad de tener "variables de alcance global" en todas las etapas. Y tener una "variable" para básicamente "almacenar el último documento" es todo lo que necesita para lograr su resultado.

Por lo tanto, es un código bastante simple y, de hecho, no se requiere una "reducción":

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

Lo que te da un resultado muy parecido a 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
}

Eso es simplemente elegir "algo único" como el _id emitido valor en lugar de algo específico, porque todo lo que realmente está haciendo es la diferencia entre valores en diferentes documentos.

Las variables globales suelen ser la solución a este tipo de agregaciones de "emparejamiento" o la producción de "totales acumulados". En este momento, el marco de agregación no tiene acceso a las variables globales, aunque podría ser bueno tener esto. El marco mapReduce los tiene, por lo que probablemente sea justo decir que también deberían estar disponibles para el marco de agregación.

Ahora mismo no lo son, así que quédese con mapReduce.