MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Precisa encontrar o valor que ocorre com mais frequência de um campo em um agregado


Bem, você não pode simplesmente "fazer as pazes". operadores como $mode não é um operador de agregação, e as únicas coisas que você pode usar são aquelas que realmente existe .

Portanto, para retornar o valor da categoria dentro do período de tempo agrupado que mais ocorre, é necessário agrupar primeiro em cada um desses valores e retornar a contagem de ocorrências. Em seguida, você pode ordenar esses resultados por essa contagem e retornar o valor da categoria que registrou a contagem mais alta nesse 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" }
    }}

Então $group na data e na categoria e mantenha a contagem de categorias por meio de $sum . Então você $sort portanto, a maior "contagem" está no topo de cada data agrupada. E, finalmente, use $first quando você aplica outro $group que é aplicado apenas à própria data, para retornar aquela categoria com a maior contagem para cada data.

Não seja tentado por operadores como $max pois não funcionam aqui. A principal diferença é a relação "vinculada" ao "registro/documento" produzido para cada valor de categoria. Portanto, não é a "contagem" máxima que você deseja ou o valor máximo da "categoria", mas sim o valor da categoria que "produziu" a maior contagem. Portanto, existe um $sort preciso aqui.

Finalmente alguns hábitos que você “deveria” quebrar:

  • Não use dados de instância de data de formato não UTC como entrada, a menos que você realmente saiba o que está fazendo. As datas sempre serão convertidas para UTC, portanto, pelo menos nas listagens de teste, você deve se acostumar a especificar o valor da data dessa maneira.

  • Pode parecer um pouco mais limpo do outro lado, mas coisas como 1000 * 60 * 60 são um código muito mais descritivo do que está fazendo do que 3600000 . Mesmo valor, mas uma forma é indicativa de suas unidades de tempo de relance.

  • Compondo _id quando há apenas um único valor também pode confundir problemas. Portanto, há pouco sentido em acessar _id.dt se esse fosse o único valor presente. Quando há mais de uma única propriedade dentro de _id então está bem. Mas valores únicos devem ser atribuídos de volta a _id sozinho. Nada ganhou de outra forma, e single é bastante claro.