Dies verdient möglicherweise eine vollständige Erklärung für diejenigen, die danach suchen könnten, also füge eine für die Nachwelt hinzu.
Was zurückgegeben wird, ist insbesondere ein Ereignisstrom für node.js, der den stream.Readable Schnittstelle mit ein paar praktischen Methoden. Ein .count()
gehört derzeit nicht dazu und würde angesichts der aktuell verwendeten Schnittstelle nicht viel Sinn machen.
Ähnlich dem Ergebnis, das vom .stream()
Methode, die Cursorobjekten zur Verfügung steht, würde ein "Zählen" hier nicht viel Sinn machen, wenn Sie die Implementierung betrachten, da es als "Stream" verarbeitet werden soll, wo Sie schließlich ein "Ende" erreichen, aber ansonsten nur verarbeiten möchten bis dahin.
Wenn Sie die standardmäßige "Cursor"-Schnittstelle des Treibers betrachtet haben, gibt es einige solide Gründe, warum der Aggregationscursor nicht derselbe ist:
-
Cursor ermöglichen die Verarbeitung von "Modifikator"-Aktionen vor der Ausführung. Diese fallen in die Kategorien
.sort()
,.limit()
und.skip()
. Alle diese haben tatsächlich Gegendirektiven im Aggregationsframework, die in der Pipeline spezifiziert sind. Als Pipeline-Stufen, die "überall" und nicht nur als Nachbearbeitungsoption für eine einfache Abfrage erscheinen könnten, würde es nicht viel Sinn machen, dieselbe "Cursor"-Verarbeitung anzubieten. -
Andere Cursor-Modifikatoren beinhalten Specials wie
.hint()
,.min()
und.max()
Dies sind Änderungen an der "Indexauswahl" und -verarbeitung. Während diese für die Aggregationspipeline von Nutzen sein könnten, gibt es derzeit keine einfache Möglichkeit, diese in die Abfrageauswahl einzubeziehen. Meistens überschreibt die Logik aus dem vorherigen Punkt jeden Punkt der Verwendung des gleichen Schnittstellentyps für einen "Cursor".
Die anderen Überlegungen sind, was Sie tatsächlich mit einem Cursor tun möchten und warum Sie einen zurückgeben "wollen". Da ein Cursor normalerweise eine "Einwegfahrt" in dem Sinne ist, dass sie normalerweise nur bis zum Erreichen eines Endes und in verwendbaren "Batches" verarbeitet werden, lässt dies einen vernünftigen Schluss zu, dass die "Zählung" tatsächlich am Ende kommt. wenn diese "Warteschlange" tatsächlich leer ist.
Es stimmt zwar, dass die standardmäßige „Cursor“-Implementierung tatsächlich einige Tricks enthält, aber der Hauptgrund dafür ist, dass dies nur ein „Meta“-Datenkonzept erweitert, da die Abfrageprofilierungs-Engine eine bestimmte Anzahl von Dokumenten „scannen“ muss, um zu bestimmen, welches Elemente, die im Ergebnis zurückgegeben werden sollen.
Das Aggregations-Framework spielt jedoch ein wenig mit diesem Konzept. Da es nicht nur die gleichen Ergebnisse gibt, die durch den Standardabfrageprofiler verarbeitet würden, sondern auch zusätzliche Phasen. Jede dieser Stufen hat das Potenzial, die resultierende „Anzahl“ zu „modifizieren“, die tatsächlich in dem zu verarbeitenden „Stream“ zurückgegeben würde.
Nochmals, wenn Sie dies aus akademischer Sicht betrachten und sagen möchten:"Sicher, die Abfragemaschine sollte die 'Metadaten' für die Zählung behalten, aber können wir nicht nachverfolgen, was danach geändert wird?". Dies wäre ein faires Argument, und Pipeline-Betreiber wie $match
und $group
oder $unwind
und möglicherweise sogar $project
und der neue $redact
, könnten alle als vernünftiger Fall angesehen werden, um die „verarbeiteten Dokumente“ in jeder Pipeline-Phase selbst zu verfolgen und diese in den „Metadaten“ zu aktualisieren, die möglicherweise zurückgegeben werden könnten, um die vollständige Pipeline-Ergebniszahl zu erklären.
Das letzte Argument ist vernünftig, aber bedenken Sie auch, dass die Implementierung eines „Cursor“-Konzepts für die Ergebnisse der Aggregationspipeline derzeit ein neues Konzept für MongoDB ist. Es könnte durchaus argumentiert werden, dass alle „vernünftigen“ Erwartungen am ersten Entwurfspunkt darin bestanden hätten, dass „die meisten“ Ergebnisse aus dem Kombinieren von Dokumenten keine Größe hätten, die die BSON-Beschränkungen einschränken würde. Aber wenn die Nutzung zunimmt, ändern sich die Wahrnehmungen und die Dinge ändern sich, um sich anzupassen.
Dies "könnte" also möglicherweise geändert werden, ist aber nicht so, wie es "derzeit" implementiert ist. Während .count()
bei einer Standard-Cursor-Implementierung Zugriff auf die "Metadaten" hat, in denen die gescannte Zahl aufgezeichnet ist, würde jede Methode bei der aktuellen Implementierung zum Abrufen aller Cursor-Ergebnisse führen, genau wie .itcount()
tut in der Shell.
Verarbeiten Sie die „Cursor“-Elemente, indem Sie auf das „data“-Ereignis zählen und am Ende etwas (möglicherweise einen JSON-Stream-Generator) als „count“ ausgeben. Für jeden Anwendungsfall, der eine Zählung "im Voraus" erfordern würde, scheint dies ohnehin keine gültige Verwendung für einen Cursor zu sein, da die Ausgabe sicherlich ein ganzes Dokument von angemessener Größe wäre.