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

Agregado Mongodb, Como contar documentos por critérios de intervalo?


O que você quer é o $cond operador e algumas condições aninhadas com $and . Mas isso deve lhe dar exatamente o que você quer.
db.collection.aggregate([
    {"$group": {
      "_id": {"$cond": [
          {"$gte": ["$LoadTime", 2000] },
          "Slowest",                                   // return "Slowest" where true
          {"$cond": [
              {"$and": [
                  {"$lt": ["$LoadTime", 2000] },
                  {"$gte": ["$LoadTime", 1000] }
              ]},
              "Slow",                                  // then "Slow" here where true
              {"$cond": [
                  {"$and": [
                      {"$lt": ["$LoadTime", 1000] },
                      {"$gte": ["$LoadTime", 500 ] }
                  ]},
                  "Medium",                            // then "Medium" where true
                  "Fast"                               // and finally "Fast" < 500
              ]}
          ]}
      ]},
      "count": {"$sum": 1}
    }},
    {"$sort": { "count": 1 }}
])

Como seu tempo é inteiro milissegundos você pode ver porque eu pedi a edição.

Assim como $cond é um ternário operador, leva três argumentos sendo:
  • Uma condição para avaliar que retorna um booleano
  • Um valor de retorno em que a condição é true
  • Um valor de retorno em que a condição é falsa

Portanto, a ideia é aninhar todas as condições, passando para o próximo teste em falso até encontrar uma condição para corresponder e um valor para retornar.

O $ e parte é uma matriz de condições incluir. Isso fornece os intervalos . Então, nas partes mais longas:
          {"$cond": [                             // Evaluate here
              {"$and": [                          // Within the range of the next 2
                  {"$lt": ["$LoadTime", 2000] },
                  {"$gte": ["$LoadTime", 1000] }
              ]},
              "Slow",                            // true condition - return
              {"$cond": [                        // false - move to next eval

Em cascata, você fica com "Rápido" por times menos de 500 milissegundos.

Cada uma dessas keys é emitido para o grupo e nós apenas { $sum: 1 } para obter uma contagem à medida que são agrupados.

Se você precisar disso em sua própria implementação de linguagem, todo o pipeline conteúdo dentro

é apenas JSON, então você pode analisá-lo em sua estrutura de dados nativa se a tradução manual lhe escapar ou se, como eu, você for apenas preguiçoso.

EDITAR


Devido aos comentários parece necessário explicar a forma da consulta apresentada. Então aqui o adendo de edição para esclarecimento.

Quando aprender uso do pipeline de agregação e, de fato, boas práticas para escrever e testar uma série complexa de estágios ou lógica, acho útil visualizar os resultados implementando partes um passo de cada vez . Então, no caso de escrever algo assim, meu primeiro passo seria o seguinte:
db.collection.aggregate([
    {"$group": {
      "_id": {"$cond": [
          {"$gte": ["$LoadTime", 2000] },
          "Slowest",
          null
       ]}
    }}
])

Agora, isso me daria a contagem de "Mais lento" como eu esperaria e, em seguida, bucket todo o resto em null . Portanto, há uma fase em que vejo os resultados até agora. Mas ao testar Na verdade, eu faria algo assim antes de prosseguir para construir uma cadeia:
db.collection.aggregate([
    {"$group": {
      "_id": {"$cond": [
          {"$and": [
              {"$lt": ["$LoadTime", 2000] },
              {"$gte": ["$LoadTime", 1000] }
          ]},
          "Slow",
          null
      ]}
    }}
])

Então, estou apenas obtendo os resultados para "Lento" (entre 2000 e 1000) com todo o resto no null balde. Portanto, minha contagem geral permanece a mesma.

Na final consulta, como foi apontado, em um ternário condição aninhada como esta, a primeira palco avaliou false para os itens que estão sendo testados pelo próximo operador. Isso significa que eles não maior que o valor que já foi testado no primeiro estágio, e isso evita a necessidade de testar essa condição para que isso poderia ser escrito da seguinte forma:
db.collection.aggregate([
    {"$group": {
      "_id": {"$cond": [
          {"$gte": ["$LoadTime", 2000] },       // Caught everything over 2000
          "Slowest",
          {"$cond": [
              {"$gte": ["$LoadTime", 1000] }    // Catch things still over 1000
              "Slow",
              {"$cond": [                       // Things under 1000 go here

              // and so on

E que curtos-circuitos a avaliação, pois não há real precisa testar coisas que não vão passar para a próxima condição lógica.

Então puramente por razões visuais e por pura preguiça de cortar e colar lógica, acabamos com o formulário expandido usando o $ e condição para envolver o intervalo. Mas para aqueles não acostumados o uso do ternário forma há uma indicação visual clara que os resultados correspondentes nesta fase ficarão entre os valores de 2000ms e 1000ms , e assim por diante, que é o que você deseja como resultado em cada intervalo.

Como eu disse, desnecessário ter por causa de como a lógica funciona, mas foi uma fase de desenvolvimento e é claro para as pessoas que ainda não compreenderam uso do ternário formulário que $cond fornece.