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

agrupar datos de colección por múltiples campos mongodb

Con el marco de agregación, el resultado será ligeramente diferente de su salida "deseada" ya que en lugar de tener claves hash, obtiene una matriz de objetos con el _id clave que tiene un valor que representa su grupo por campo. Por ejemplo, en lugar de

{
    "28-10-2016":{
        "success_count": 10, 
        "failure_count": 10
    },
    "29-10-2016": {
        "success_count": 10, 
        "failure_count": 10
    }
}

tendrías una mejor estructura como

[
    {
        "_id": "28-10-2016",
        "success_count": 10, 
        "failure_count": 10
    },
        "_id": "29-10-2016",
        "success_count": 10, 
        "failure_count": 10
    }
]

Lograr el resultado anterior requeriría el uso de $cond operador en el $sum operador acumulador El $cond El operador evaluará una condición lógica basada en su primer argumento (si) y luego devuelve el segundo argumento donde la evaluación es verdadera (entonces) o el tercer argumento donde es falso (else). Esto convierte la lógica verdadero/falso en valores numéricos 1 y 0 que se alimentan en $sum respectivamente:

"success_count": {
    "$sum": {
        "$cond": [ { "$eq": [ "$status", "success" ] }, 1, 0 ]
    }
}

Como canalización resultante, es necesario ejecutar la operación de agregación que utiliza $dateToString operador en el _id expresión clave para el $group canalización:

Orders.aggregate([
    {
        "$group": {
            "_id": {
                "$dateToString": { 
                    "format": "%Y-%m-%d", 
                    "date": "$created_at" 
                }
            },
            "success_count": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$status", "success" ] }, 1, 0 ]
                }
            },
            "failure_count": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$status", "failure" ] }, 1, 0 ]
                }
            }
        }
    }
], function (err, orders){
    if (err) throw err;
    console.log(orders);
})

Sin embargo, existe un enfoque más flexible y de mejor rendimiento que se ejecuta mucho más rápido que el anterior, donde la estructura de datos más eficiente para el resultado de su agregación sigue el esquema, por ejemplo:

orders = [
    {
        "_id": "28-10-2016",
        "counts": [
            { "status": "success", "count": 10 },
            { "status": "failure", "count": 10 }
        ]
    },
    {
        "_id": "29-10-2016",
        "counts": [
            { "status": "success", "count": 10 },
            { "status": "failure", "count": 10 }
        ]
    }
]

Luego considere ejecutar una canalización alternativa de la siguiente manera

Orders.aggregate([
    { 
        "$group": {
            "_id": { 
                "date":  {
                    "$dateToString": { 
                        "format": "%Y-%m-%d", 
                        "date": "$created_at" 
                    }
                },
                "status": { "$toLower": "$status" }
            },
            "count": { "$sum": 1 }
        }
    },
    { 
        "$group": {
            "_id": "$_id.date",
            "counts": {
                "$push": {
                    "status": "$_id.status",
                    "count": "$count"
                }
            }
        }
    }
], function (err, orders){
    if (err) throw err;
    console.log(orders);
})