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

Necesidad de encontrar el valor más frecuente de un campo en un agregado

Bueno, no puedes simplemente "hacer las paces". operadores como $mode no es un operador de agregación, y las únicas cosas que puede usar son aquellas que existen realmente .

Entonces, para devolver el valor de la categoría dentro del período de tiempo agrupado que ocurre más, es necesario agrupar primero en cada uno de esos valores y devolver el recuento de ocurrencias. Luego puede ordenar estos resultados por ese conteo y devolver el valor de categoría que registró el conteo más alto dentro de ese período:

    // Filter dates
    { "$match": { 
        "dt": { 
            "$gt": new Date("October 13, 2010 12:00:00"), 
            "$lt": new Date("November 13, 2010 12:00:00")
        } 
    }},

    // Group by hour and category, with avg and count
    { "$group": {
        "_id": {
            "dt": {
                "$add": [
                    {
                        "$subtract": [
                            { "$subtract": ["$dt", new Date(0)] },
                            {
                                "$mod": [
                                    { "$subtract": ["$dt", new Date(0)] },
                                    3600000//1000 * 60 * 60
                                ]
                            }
                        ]
                    },
                    new Date(0)
                ]
            },
            "category": "$category"
        }, 
        "price": { "$avg": "$price" },
        "count": { "$sum": 1 }
    }},
    // Sort on date and count
    { "$sort": { "_id.dt": 1, "count": -1 }},

    // Group on just the date, keeping the avg and the first category
    { "$group": {
        "_id": "$_id.dt",
        "price": { "$avg": "$price"}
        "category": { "$first": "$_id.category" }
    }}

Entonces $group tanto en la fecha como en la categoría y conservar el recuento de categorías a través de $sum . Entonces usted $sort por lo tanto, el "recuento" más grande está arriba para cada fecha agrupada. Y finalmente use $first cuando aplica otro $group eso solo se aplica a la fecha en sí, para devolver esa categoría con el recuento más grande para cada fecha.

No se deje tentar por operadores como $max ya que no trabajan aquí. La diferencia clave es la relación "vinculada" con el "registro/documento" producido para cada valor de categoría. Por lo tanto, no es el "recuento" máximo lo que desea o el valor máximo de "categoría", sino el valor de categoría que "produjo" el recuento más grande. Por lo tanto, hay un $sort necesario aquí.

Finalmente, algunos hábitos que "deberías" romper:

  • No utilice datos de instancia de fecha en formato no UTC como entrada a menos que realmente sepa lo que está haciendo. Las fechas siempre se convertirán a UTC, por lo que al menos en las listas de prueba, debe acostumbrarse a especificar el valor de la fecha de esa manera.

  • Podría verse un poco más limpio de otra manera, pero cosas como 1000 * 60 * 60 son un código mucho más descriptivo de lo que está haciendo que 3600000 . Mismo valor, pero una forma es indicativa de sus unidades de tiempo de un vistazo.

  • Compuesto _id cuando solo hay un valor único también puede confundir los problemas. Así que no tiene mucho sentido acceder a _id.dt si ese fuera el único valor presente. Cuando hay más de una sola propiedad dentro de _id entonces esta bien Pero los valores individuales deben asignarse directamente a _id solo. Nada ganado de otra manera, y solo es bastante claro.