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

Mongodb-Aggregat, Wie werden Dokumente nach Intervallkriterien gezählt?

Was Sie wollen, ist $cond Operator und einige verschachtelte Bedingungen mit $and . Aber das sollte Ihnen genau das geben, was Sie wollen.

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

Denn Ihre Zeit ist vollständig Millisekunden können Sie sehen, warum ich um die Bearbeitung gebeten habe.

Also als $cond ist ein ternary Operator, benötigt er drei Argumente:

  • Eine auszuwertende Bedingung, die einen booleschen Wert zurückgibt
  • Ein Rückgabewert, bei dem die Bedingung wahr ist
  • Ein Rückgabewert, bei dem die Bedingung falsch ist

Daher ist die Idee, dass Sie nisten die Bedingungen durchgängig und bewegen Sie sich zum nächsten Test auf false bis Sie eine passende Bedingung und einen zurückzugebenden Wert gefunden haben.

Das $und part ist ein Array von Bedingungen einschließen. Dadurch erhalten Sie die Bereiche . Also in den längsten Teilen:

          {"$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

Wenn Sie durch Sie kaskadieren, bleibt times "Schnell". unter 500 Millisekunden.

Jeder dieser keys wird an die Gruppe ausgegeben und wir verwenden nur { $sum: 1 } um eine Zählung zu erhalten, wenn sie gruppiert sind.

Wenn Sie das in Ihrer eigenen Sprachimplementierung benötigen, die gesamte pipeline Inhalt innerhalb von

ist nur JSON, also können Sie das in Ihre native Datenstruktur parsen, wenn Ihnen das Übersetzen per Hand ausgeht oder wenn Sie wie ich einfach nur faul sind.

BEARBEITEN

Aufgrund der Kommentare es scheint notwendig, das Formular zu erklären der präsentierten Abfrage. Hier also der Edit-Nachtrag zur Klarstellung.

Beim Lernen Nutzung der Aggregationspipeline und in der Tat gute Praxis zum Ausschreiben und Testen eine komplexe Reihe von Phasen oder Logik, ich finde es nützlich, sie zu visualisieren die Ergebnisse durch die Implementierung von Teilen Schritt für Schritt . Also in dem Fall, dass ich so etwas zuerst schreibe Schritt wäre wie folgt:

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

Nun, das würde mir wie erwartet die Zählung von "Slowest" und dann bucket geben alles andere in null . Es gibt also eine Phase, in der ich die bisherigen Ergebnisse sehe. Aber beim Testen Ich würde eigentlich so etwas tun, bevor ich mit dem Aufbau einer Kette fortfahre:

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

Ich erhalte also nur die Ergebnisse für "Langsam" (zwischen 2000 und 1000) mit allem anderen im null Eimer. Meine Gesamtzahl bleibt also gleich.

Im Finale Abfrage, wie bereits erwähnt, in einem ternary Bedingung, die so verschachtelt ist, die erste Stufe hat bereits false ausgewertet für die Artikel, die vom nächsten getestet werden Operator. Das bedeutet, dass sie es nicht sind größer als der Wert, der bereits im ersten getestet wurde Stufe, und das vermeidet die Notwendigkeit, auf diese Bedingung zu testen, damit dies konnte wie folgt geschrieben werden:

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

Und das Kurzschlüsse die Bewertung gibt es da nicht echt auf Dinge testen müssen, die nicht zur nächsten logischen Bedingung durchkommen.

Also rein aus optischen Gründen und für schiere Faulheit beim Ausschneiden und Einfügen Logik erhalten wir die erweiterte Form mit $and Bedingung zum umschließen die Reichweite. Aber für diejenigen, die es nicht gewohnt sind die Verwendung des ternary Form gibt es einen deutlichen visuellen Hinweis dass die in dieser Phase abgeglichenen Ergebnisse dazwischen liegen die Werte von 2000ms und 1000ms , und so weiter, was Sie als Ergebnis in jedem Bereich wünschen.

Wie gesagt, unnötig wegen der Funktionsweise der Logik, aber war es eine Entwicklungsphase und ist klar an die Leute, die noch ihren Kopf herumkriegen müssen Verwendung des ternary bilden diese $cond bietet.