sql >> Database >  >> NoSQL >> MongoDB

Een dynamische waarde gebruiken bij aggregatie

De algemene vraag hier is om het bereik op te nemen voor de "maand" waarden in overweging waar het "groter is dan" de -5 maanden "voor" en "minder dan" de +2 maanden "na" zoals vastgelegd in de "ingeschreven" array-items.

Het probleem is dat aangezien deze waarden zijn gebaseerd op "dateJoined" , moeten ze worden aangepast met het juiste interval tussen de "dateJoined" en de "dateActivated" . Dit maakt de uitdrukking effectief:

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

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

Of logisch uitgedrukt "De maanden tussen het uitgedrukte bereik aangepast door het aantal maanden verschil tussen lid worden en activeren" .

Zoals vermeld in de opmerking, is het allereerste dat u hier moet doen, deze datumwaarden opslaan als een BSON-datum in tegenstelling tot hun huidige schijnbare "string" -waarden. Zodra dat is gebeurd, kunt u de volgende aggregatie toepassen om het verschil met de opgegeven datums te berekenen en het aangepaste bereik dienovereenkomstig uit de array filteren voordat u gaat tellen:

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

Dit is dus van toepassing op dezelfde $filter naar de array die u probeerde, maar houdt nu ook rekening met de aangepaste waarden voor het bereik van maanden waarop moet worden gefilterd.

Om dit leesbaarder te maken passen we $let waarmee de gemeenschappelijke waarde kan worden berekend die is verkregen voor $$monthsDiff zoals geïmplementeerd in een variabele. Hier wordt de oorspronkelijk uitgelegde uitdrukking toegepast, met behulp van $year en $month om die numerieke waarden uit de opgeslagen datums te halen.

De aanvullende wiskundige operatoren $add gebruiken , $subtract en $multiply je kunt zowel het verschil in maanden berekenen als later toepassen om de "bereik"-waarden in de logische voorwaarden aan te passen met $gte en $lte .

Ten slotte, omdat $filter zendt een array uit van alleen de vermeldingen die voldoen aan de voorwaarden, om te "tellen" passen we $maat die de lengte van de "gefilterde" array retourneert, wat het "aantal" overeenkomsten is.

Afhankelijk van het beoogde doel kan de hele uitdrukking ook als argument worden verstrekt aan $sum als een $group accumulator, als dat inderdaad de bedoeling was.



  1. Hoe kan ik een Meteor-verzameling sorteren op tijdstip van inbrengen?

  2. Mongoexport naar meerdere csv-bestanden

  3. Spring data mongodb - integratie van aggregatieframework

  4. blpop stopt na een tijdje met het verwerken van de wachtrij