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

Agregado de Mongodb, ¿Cómo contar documentos por criterios de intervalo?

Lo que sí quieres es el $cond operador y bastantes condiciones anidadas con $and . Pero esto debería darte exactamente lo que quieres.

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 tu tiempo es completo milisegundos puedes ver por qué pedí la edición.

Así como $cond es un ternary operador, toma tres argumentos siendo:

  • Una condición para evaluar que devuelve un booleano
  • Un valor devuelto donde la condición es verdadera
  • Un valor devuelto donde la condición es falsa

Por lo tanto la idea es que tu nido las condiciones en todo momento, pasando al siguiente prueba en falso hasta que haya encontrado una condición para hacer coincidir y un valor para devolver.

El $y parte es una matriz de condiciones para incluir. Esto le da los rangos . Así que en las partes más largas:

          {"$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

En cascada, te queda "Rápido" para times menos de 500 milisegundos.

Cada una de estas keys se emite al grupo y solo { $sum: 1 } para obtener un recuento a medida que se agrupan.

Si necesita eso en su propia implementación de lenguaje, todo el pipeline contenido dentro de

es solo JSON, por lo que puede analizarlo en su estructura de datos nativos si traducir a mano se le escapa, o si, como yo, es perezoso.

EDITAR

Debido a los comentarios parece necesario explicar el formulario de la consulta presentada. Así que aquí el apéndice de edición para aclaración.

Al aprender uso de la canalización de agregación y, de hecho, buenas prácticas para escribir y probar una serie compleja de etapas o lógica, me parece útil visualizar los resultados implementando partes un paso a la vez . Entonces, en el caso de escribir tal cosa, mi primero el paso sería el siguiente:

db.collection.aggregate([
    {"$group": {
      "_id": {"$cond": [
          {"$gte": ["$LoadTime", 2000] },
          "Slowest",
          null
       ]}
    }}
])

Ahora eso me daría el conteo de "Más lento" como esperaría y luego cubo todo lo demás en null . Así que hay una etapa en la que veo los resultados hasta ahora. Pero al probar De hecho, haría algo como esto antes de pasar a construir una cadena:

db.collection.aggregate([
    {"$group": {
      "_id": {"$cond": [
          {"$and": [
              {"$lt": ["$LoadTime", 2000] },
              {"$gte": ["$LoadTime", 1000] }
          ]},
          "Slow",
          null
      ]}
    }}
])

Solo obtengo los resultados de "Lento" (entre 2000 y 1000) con todo lo demás en null balde. Así que mi recuento general sigue siendo el mismo.

En la final consulta, como se señaló, en un ternary condición anidada como esta, la primera el escenario ya evaluado false para los artículos que está probando el siguiente operador. Esto significa que no son mayor que el valor que ya se probó en la primera etapa, y eso obvia la necesidad de probar esa condición para que esto pudiera escribirse de la siguiente manera:

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

Y que cortocircuitos la evaluación ya que no hay real necesita probar cosas que no llegarán a la siguiente condición lógica.

Así que puramente por razones visuales y por pura pereza de cortar y pegar lógica, terminamos con la forma expandida usando $and condición para envolver el rango. Pero para los no acostumbrados el uso del ternary forma hay una señal visual clara que los resultados que se comparan en esta fase caerán entre los valores de 2000ms y 1000ms , y así sucesivamente, que es lo que desea como resultado en cada rango.

Como dije, innecesario debido a cómo funciona la lógica, pero era una fase de desarrollo, y es claro a las personas que todavía tienen que entrar en la cabeza uso del ternary forma que $cond proporciona.