sql >> Database teknologi >  >> NoSQL >> MongoDB

Brug af en dynamisk værdi i aggregation

Den generelle forespørgsel her er at inkludere intervallet for "month" værdier i betragtning, hvor den er "større end" -5 måneder "før" og "mindre end" +2 måneder "efter" som registreret i den "enrolled" matrixindgange.

Problemet er, at da disse værdier er baseret på "dateJoined" , skal de justeres med det korrekte interval mellem "dateJoined" og "dateActivated" . Dette gør udtrykket effektivt:

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

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

Eller logisk udtrykt "Månederne mellem det udtrykte interval justeret med antallet af måneders forskel mellem tilmelding og aktivering" .

Som angivet i kommentaren, er det allerførste, du skal her, at gemme disse datoværdier som en BSON Date i modsætning til deres nuværende tilsyneladende "streng"-værdier. Når det er gjort, kan du derefter anvende følgende aggregering for at beregne forskellen fra de angivne datoer og filtrere det justerede interval i overensstemmelse hermed fra arrayet, før du tæller:

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

Så dette gælder det samme $filter til det array, som du forsøgte, men tager nu også højde for de justerede værdier for de måneder, der skal filtreres efter.

For at gøre dette lettere at læse anvender vi $let som tillader beregning af den fælles værdi opnået for $$monthsDiff som implementeret i en variabel. Det er her, det oprindeligt forklarede udtryk anvendes ved at bruge $year og $month for at udtrække disse numeriske værdier fra de lagrede datoer.

Brug af de ekstra matematiske operatorer $add , $subtract og $multiply du kan både beregne forskellen i måneder og også senere anvende til at justere "range"-værdierne i de logiske forhold med $gte og $lte .

Endelig fordi $filter udsender en række kun de poster, der matcher betingelserne, for at "tælle" anvender vi $size som returnerer længden af ​​det "filtrerede" array, som er "antal" af matches.

Afhængigt af dit tilsigtede formål kan hele udtrykket også leveres i argument til $sum som en $group akkumulator, hvis det da virkelig var hensigten.



  1. Laravel 4 :Kald til udefineret metode Redis::connection()

  2. MongoDB starter ikke efter servernedbrud

  3. Hvordan tjekker man for nul/nul i Redis' Lua cjson?

  4. Elastisk søgning med MongoDB:Søgning i PDF-filer