MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Verwenden eines dynamischen Werts in der Aggregation

Die allgemeine Bitte hier ist, den Bereich für den "Monat" einzuschließen Werte berücksichtigt, bei denen es "größer als" -5 ist Monate "vor" und "weniger als" +2 Monate "nach", wie im Feld "registriert" angegeben Array-Einträge.

Das Problem besteht darin, dass diese Werte auf "dateJoined" basieren , müssen sie um das richtige Intervall zwischen "dateJoined" angepasst werden und der "dateActivated" . Dies macht den Ausdruck effektiv:

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

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

Oder logisch ausgedrückt "Die Monate zwischen dem ausgedrückten Bereich, angepasst um die Anzahl der Monate zwischen Beitritt und Aktivierung" .

Wie im Kommentar erwähnt, ist das allererste, was Sie hier tun müssen, diese Datumswerte als BSON Date zu speichern im Gegensatz zu ihren gegenwärtigen scheinbaren "String"-Werten. Sobald dies erledigt ist, können Sie die folgende Aggregation anwenden, um die Differenz aus den angegebenen Daten zu berechnen und den angepassten Bereich vor dem Zählen entsprechend aus dem Array zu filtern:

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

Daher gilt dasselbe $filter zu dem Array, das Sie versucht haben, berücksichtigt jetzt aber auch die angepassten Werte für den Bereich der Monate, nach denen gefiltert werden soll.

Um dies leichter lesbar zu machen, verwenden wir $let was die Berechnung des gemeinsamen Werts ermöglicht, der für $$monthsDiff erhalten wird wie in einer Variablen implementiert. Hier wird der ursprünglich erläuterte Ausdruck unter Verwendung von $year angewendet und $month um diese numerischen Werte aus den gespeicherten Daten zu extrahieren.

Verwenden der zusätzlichen mathematischen Operatoren $add , $subtract und $multiply Sie können sowohl die Differenz in Monaten berechnen als auch später beantragen, die „Range“-Werte in den logischen Bedingungen anzupassen mit $gte und $lte .

Schließlich, weil $filter gibt ein Array aus, das nur die Einträge enthält, die den Bedingungen entsprechen. Um zu „zählen“, wenden wir $size die die Länge des "gefilterten" Arrays zurückgibt, was die "Anzahl" der Übereinstimmungen ist.

Abhängig von Ihrem beabsichtigten Zweck kann der gesamte Ausdruck auch als Argument für $summe als $group Akku, wenn das denn tatsächlich so gewollt war.