MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Utilisation d'une valeur dynamique dans l'agrégation

La demande générale ici est d'inclure la plage pour le "month" valeurs en considération où il est "supérieur" au -5 mois "avant" et "moins que" le +2 mois "après" tel qu'enregistré dans le "enrolled" entrées de tableau.

Le problème est que puisque ces valeurs sont basées sur "dateJoined" , ils doivent être ajustés par l'intervalle correct entre le "dateJoined" et le "dateActivated" . Cela rend l'expression efficace :

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

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

Ou exprimé logiquement "Les mois entre la plage exprimée ajustés par le nombre de mois de différence entre l'adhésion et l'activation" .

Comme indiqué dans le commentaire, la toute première chose que vous devez faire ici est de stocker ces valeurs de date en tant que BSON Date par opposition à leurs valeurs "chaînes" apparentes actuelles. Une fois cela fait, vous pouvez ensuite appliquer l'agrégation suivante pour calculer la différence par rapport aux dates fournies et filtrer la plage ajustée en conséquence à partir du tableau avant de compter :

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" ] }
                ]
              }
            }
          } 
        }
      }
    }
  }}
])

Cela s'applique donc au même $filter au tableau que vous essayiez, mais prend désormais en compte les valeurs ajustées sur la plage de mois à filtrer également.

Pour faciliter la lecture, nous appliquons $let qui permet de calculer la valeur commune obtenue pour $$monthsDiff comme implémenté dans une variable. Voici où l'expression expliquée à l'origine est appliquée, en utilisant $year et $month pour extraire ces valeurs numériques des dates telles qu'elles sont stockées.

Utilisation des opérateurs mathématiques supplémentaires $add , $subtract et $multiply vous pouvez calculer à la fois la différence en mois et également appliquer ultérieurement pour ajuster les valeurs de "plage" dans les conditions logiques avec $gte et $lte .

Enfin, parce que $filter émet un tableau des seules entrées correspondant aux conditions, afin de "compter" nous appliquons $size qui renvoie la longueur du tableau "filtré", qui est le "nombre" de correspondances.

En fonction de votre objectif, l'expression entière peut également être fournie en argument de $sum en tant que $group accumulateur, si c'était bien l'intention.