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

Mongodb:consulte los totales de hoy, los totales de la semana y los totales del mes en una consulta

Esto es más una cuestión de cómo espera que se vea la salida, ya que cualquier resultado agregado esencialmente necesita agruparse en el nivel más bajo y luego agruparse progresivamente en "granos" más altos hasta alcanzar el nivel más alto ("mes"). Este tipo de implica datos agrupados por "mes" en última instancia, a menos que los desglose de otra manera.

En esencia, progresivamente $group :

db.collection.aggregate([
    // First total per day. Rounding dates with math here
    { "$group": {
        "_id": {
            "$add": [
                { "$subtract": [
                    { "$subtract": [ "$createdAt", new Date(0) ] },
                    { "$mod": [
                        { "$subtract": [ "$createdAt", new Date(0) ] },
                        1000 * 60 * 60 * 24
                    ]}                        
                ]},
                new Date(0)
            ]
        },
        "week": { "$first": { "$week": "$createdAt" } },
        "month": { "$first": { "$month": "$createdAt" } },
        "total": { "$sum": "$num" }
    }},

    // Then group by week
    { "$group": {
        "_id": "$week",
        "month": { "$first": "$month" },
        "days": {
            "$push": {
                "day": "$_id",
                "total": "$total"
            }
        },
        "total": { "$sum": "$total" }
    }},

    // Then group by month
    { "$group": {
        "_id": "$month",
        "weeks": {
            "$push": {
                "week": "$_id",
                "total": "$total",
                "days": "$days"
            }
        },
        "total": { "$sum": "$total" }
    }}
])

Entonces, cada nivel después del primero que se suma por día se inserta progresivamente en el contenido de la matriz para su valor "redondeado" y los totales también se suman en ese nivel.

Si desea una salida más plana con un registro por día que contenga los totales semanales y mensuales, así como el total del día, agregue dos $unwind declaraciones al final de la canalización:

{ "$unwind": "$weeks" },
{ "$unwind": "$weeks.days" }

Y opcionalmente $project los campos "punteados" a algo más plano y legible si es necesario.

Si está abarcando "años" con esto, incluya dicha operación en la clave de agrupación al menos desde el nivel de "semana" para que no esté posiblemente combinando datos de diferentes años y estén separados.

También es mi preferencia general usar "fecha matemática" enfoque al redondear fechas ya que devuelve una Date objeto, pero como se usa en otros niveles además de "día", puede usar alternativamente operadores de agregación de fecha en su lugar.

No es necesario mapReduce ya que esto es bastante intuitivo y hay una cantidad finita de días en un mes, lo que significa que el límite de BSON al anidar matrices en el contenido mientras se agrega no se romperá.