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

Uso de un valor dinámico en la agregación

La pregunta general aquí es incluir el rango para el "month" valores en consideración donde es "mayor que" el -5 meses "antes" y "menos de" el +2 meses "después" como se registra en el "enrolled" entradas de matriz.

El problema es que, dado que estos valores se basan en "dateJoined" , deben ajustarse según el intervalo correcto entre "dateJoined" y el "dateActivated" . Esto hace que la expresión sea efectiva:

monthsDiff = (yearActivated - yearJoined)*12 + (monthActivated - monthJoined)

where month >= ( startRange + monthsDiff ) and month <= ( endRange + monthsDiff )
and enrolled = "01"

O expresado lógicamente "Los meses entre el rango expresado ajustado por el número de meses de diferencia entre unirse y activar" .

Como se indica en el comentario, lo primero que debe hacer aquí es almacenar esos valores de fecha como BSON Date a diferencia de sus valores de "cadena" aparentes actuales. Una vez hecho esto, puede aplicar la siguiente agregación para calcular la diferencia de las fechas proporcionadas y filtrar el rango ajustado en consecuencia de la matriz antes de contar:

var rangeStart = -5,
    rangeEnd = 2;

db.getCollection('enrollments').aggregate([
  { "$project": {
    "enrollments": {
      "$size": {
        "$filter": {
          "input": "$enrolled",
          "as": "e",
          "cond": {
            "$let": {
              "vars": {
                "monthsDiff": {
                  "$add": [
                    { "$multiply": [
                      { "$subtract": [
                        { "$year": "$dateActivated" },
                        { "$year": "$dateJoined" }
                      ]},
                      12
                    }},
                    { "$subtract": [
                      { "$month": "$dateActivated" },
                      { "$month": "$dateJoined" }
                    ]}
                  ]
                }
              },
              "in": {
                "$and": [
                  { "$gte": [ { "$add": [ rangeStart, "$$monthsDiff" ] }, "$$e.month" ] },
                  { "$lte": [ { "$add": [ rangeEnd, "$$monthsDiff" ] }, "$$e.month" ] },
                  { "$eq": [ "$$e.enrolled", "01" ] }
                ]
              }
            }
          } 
        }
      }
    }
  }}
])

Entonces esto aplica lo mismo $filter a la matriz que estaba intentando, pero ahora también tiene en cuenta los valores ajustados en el rango de meses para filtrar.

Para que sea más fácil de leer, aplicamos $let que permite calcular el valor común obtenido para $$monthsDiff como implementado en una variable. Aquí es donde se aplica la expresión explicada originalmente, usando $year y $month para extraer esos valores numéricos de las fechas almacenadas.

Usando los operadores matemáticos adicionales $add , $subtract y $multiply puede calcular la diferencia en meses y luego aplicar para ajustar los valores de "rango" en las condiciones lógicas con $gte y $lte .

Finalmente, porque $filter emite una matriz de solo las entradas que coinciden con las condiciones, para "contar" aplicamos $size que devuelve la longitud de la matriz "filtrada", que es el "recuento" de coincidencias.

Según el propósito previsto, la expresión completa también se puede proporcionar como argumento para $sum como $group acumulador, si entonces era realmente la intención.