sql >> Databasteknik >  >> NoSQL >> MongoDB

Använda ett dynamiskt värde i aggregation

Den allmänna frågan här är att inkludera intervallet för "month" värden i beaktande där det är "större än" -5 månader "före" och "mindre än" +2 månader "efter" som registrerats i "enrolled" arrayposter.

Problemet är att eftersom dessa värden är baserade på "dateJoined" , måste de justeras med rätt intervall mellan "dateJoined" och "dateActivated" . Detta gör uttrycket effektivt:

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

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

Eller logiskt uttryckt "Månader mellan det uttryckta intervallet justerat med antalet månaders skillnad mellan att gå med och aktivera" .

Som nämnts i kommentaren är det allra första du behöver här att lagra dessa datumvärden som ett BSON Date i motsats till deras nuvarande skenbara "strängvärden". När det är gjort kan du sedan använda följande aggregering för att beräkna skillnaden från de angivna datumen och filtrera det justerade intervallet i enlighet därmed från matrisen innan du räknar:

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å detta gäller samma $filter till den array som du försökte, men tar nu även hänsyn till de justerade värdena för månadsintervallet att filtrera efter.

För att göra detta lättare att läsa använder vi $let som tillåter beräkning av det gemensamma värdet som erhålls för $$monthsDiff som implementerat i en variabel. Här används uttrycket som ursprungligen förklarades, med $year och $month för att extrahera dessa numeriska värden från de lagrade datumen.

Använda de ytterligare matematiska operatorerna $add , $subtract och $multiply du kan beräkna både skillnaden i månader och även senare tillämpa för att justera "intervall"-värdena i de logiska förhållandena med $gte och $lte .

Slutligen, eftersom $filter skickar ut en rad endast poster som matchar villkoren, för att "räkna" tillämpar vi $size som returnerar längden på den "filtrerade" arrayen, vilket är "antal" av matchningar.

Beroende på ditt avsedda syfte kan hela uttrycket också tillhandahållas i argument till $sum som en $group ackumulator, om det då verkligen var avsikten.



  1. Heroku förkompilerade tillgångar misslyckades

  2. Skapar BSON-objekt från JSON-sträng

  3. Antal anslutningar till MongoDB-servern

  4. Hur man ersätter befintliga dokument när man importerar en fil till MongoDB