sql >> Databasteknik >  >> NoSQL >> MongoDB

Mongodb aggregat, Hur räknar man dokument efter intervallkriterier?

Det du vill ha är $cond operator och en hel del kapslade villkor med $and . Men det här borde ge dig precis vad du vill ha.

db.collection.aggregate([
    {"$group": {
      "_id": {"$cond": [
          {"$gte": ["$LoadTime", 2000] },
          "Slowest",                                   // return "Slowest" where true
          {"$cond": [
              {"$and": [
                  {"$lt": ["$LoadTime", 2000] },
                  {"$gte": ["$LoadTime", 1000] }
              ]},
              "Slow",                                  // then "Slow" here where true
              {"$cond": [
                  {"$and": [
                      {"$lt": ["$LoadTime", 1000] },
                      {"$gte": ["$LoadTime", 500 ] }
                  ]},
                  "Medium",                            // then "Medium" where true
                  "Fast"                               // and finally "Fast" < 500
              ]}
          ]}
      ]},
      "count": {"$sum": 1}
    }},
    {"$sort": { "count": 1 }}
])

Eftersom din tid är hel millisekunder kan du se varför jag bad om redigeringen.

Så som $cond är en ternär operatör, det krävs tre argument som är:

  • Ett villkor för att utvärdera som returnerar en boolean
  • Ett returvärde där villkoret är sant
  • Ett returvärde där villkoret är falskt

Därför är tanken att du bo förhållandena genomgående, flytta till nästa testa på false tills du har hittat ett villkor att matcha och ett värde att returnera.

$and del är en rad villkor att inkludera. Detta ger dig intervallen . Så i de längsta delarna:

          {"$cond": [                             // Evaluate here
              {"$and": [                          // Within the range of the next 2
                  {"$lt": ["$LoadTime", 2000] },
                  {"$gte": ["$LoadTime", 1000] }
              ]},
              "Slow",                            // true condition - return
              {"$cond": [                        // false - move to next eval

Kaskad genom dig lämnas med "Snabb" i times under 500 millisekunder.

Var och en av dessa keys sänds ut till gruppen och vi bara { $sum: 1 } för att få en räkning när de är grupperade.

Om du behöver det i din egen språkimplementering, hela pipeline innehåll inom

är bara JSON, så du kan analysera det i din inhemska datastruktur om du undviker att översätta för hand, eller om du som jag bara är lat.

REDIGERA

På grund av kommentarerna det verkar nödvändigt att förklara formen av den presenterade frågan. Så här redigeringstillägget för förtydligande.

När du lär dig användning av aggregeringspipelinen och faktiskt god praxis för att skriva ut och testa en komplex serie av steg eller logik, tycker jag att det är användbart att visualisera resultaten genom att implementera delar ett steg i taget . Så i fallet med att skriva en sådan sak min första steg skulle vara som följer:

db.collection.aggregate([
    {"$group": {
      "_id": {"$cond": [
          {"$gte": ["$LoadTime", 2000] },
          "Slowest",
          null
       ]}
    }}
])

Nu skulle det ge mig räkningen av "Långsammast" som jag förväntade mig och sedan hink allt annat till null . Så det finns ett skede där jag ser resultaten hittills. Men när du testar Jag skulle faktiskt göra något liknande innan jag gick vidare för att bygga upp en kedja:

db.collection.aggregate([
    {"$group": {
      "_id": {"$cond": [
          {"$and": [
              {"$lt": ["$LoadTime", 2000] },
              {"$gte": ["$LoadTime", 1000] }
          ]},
          "Slow",
          null
      ]}
    }}
])

Så jag får bara resultaten för "Långsamt" (mellan 2000 och 1000) med allt annat i null hink. Så mitt totala antal förblir detsamma.

I finalen fråga, som påpekades, i en ternär villkor som är kapslat som det här, första scenen har redan utvärderad false för de artiklar som testas av nästa operatör. Det betyder att de inte är det större än värdet som redan testades i första skede, och det undviker behovet av att testa för det tillståndet så att detta kunde skrivas enligt följande:

db.collection.aggregate([
    {"$group": {
      "_id": {"$cond": [
          {"$gte": ["$LoadTime", 2000] },       // Caught everything over 2000
          "Slowest",
          {"$cond": [
              {"$gte": ["$LoadTime", 1000] }    // Catch things still over 1000
              "Slow",
              {"$cond": [                       // Things under 1000 go here

              // and so on

Och att kortslutningar utvärderingen eftersom det inte finns någon riktig måste testa för saker som inte kommer fram till nästa logiska tillstånd.

Alltså rent av visuella skäl och för ren lathet att klippa och klistra logik slutar vi med den utökade formen med $and villkor för att linda räckvidden. Men för dem som inte är vana vid användningen av ternary från det finns en tydlig visuell signal att resultaten som matchas i denna fas kommer att falla mellan värdena för 2000ms och 1000ms , och så vidare, vilket är vad du vill ha som resultat i varje intervall.

Som sagt onödigt att ha på grund av hur logiken fungerar, men det var en utvecklingsfas och är tydlig till de människor som ännu inte har förstått sina huvuden användning av ternary bildar den $cond ger.




  1. Frågar Morphia av Id

  2. Är master alltid omdisponerad instans med minsta prioritet?

  3. Vilken noSQL-databas är bäst för insättningar/skrivningar med hög volym?

  4. Hur man kaskadraderar dokument i mongodb?