Der Fehler liegt daran, dass es kein Array mehr ist, nachdem Sie $unwind
und daher kein gültiges Argument mehr für $size
.
Sie scheinen zu versuchen, einige vorhandene Antworten "zusammenzuführen", ohne zu verstehen, was sie tun. Was Sie hier wirklich wollen, ist $filter
und $size
db.collection.aggregate([
{ "$project": {
"total": {
"$size": {
"$filter": {
"input": "$Array",
"cond": { "$eq": [ "$$this.field1", "a" ] }
}
}
}
}}
])
Oder „erfinden Sie das Rad neu“ mit $reduce
:
db.collection.aggregate([
{ "$project": {
"total": {
"$reduce": {
"input": "$Array",
"initialValue": 0,
"in": {
"$sum": [
"$$value",
{ "$cond": [{ "$eq": [ "$$this.field1", "a" ] }, 1, 0] }
}
}
}
}}
])
Oder für das, was Sie mit $unwind/ machen wollten. Code>
, Sie tatsächlich $group
erneut, um zu "zählen", wie viele Übereinstimmungen es gab:
db.collection.aggregate([
{ "$unwind": "$Array" },
{ "$match": { "Array.field1": "a" } },
{ "$group": {
"_id": "$_id",
"total": { "$sum": 1 }
}}
])
Die ersten beiden Formen sind die "optimalen" für moderne MongoDB-Umgebungen. Die endgültige Form mit $unwind
und $group
ist ein "Legacy"-Konstrukt, das für diese Art von Operation seit MongoDB 2.6 wirklich nicht mehr notwendig war, wenn auch mit einigen leicht anderen Operatoren.
In den ersten beiden vergleichen wir im Wesentlichen das field1
Wert jedes Array-Elements, solange es noch ein Array ist. Beide $filter
und $reduce
sind moderne Operatoren, die dafür ausgelegt sind, mit einem vorhandenen Array zu arbeiten. Derselbe Vergleich wird bei jedem unter Verwendung der Aggregation $eq durchgeführt
-Operator, der einen booleschen Wert zurückgibt, je nachdem, ob die angegebenen Argumente "gleich" sind oder nicht. In diesem Fall auf jedem Arraymitglied auf den erwarteten Wert von "a"
.
Im Fall von $filter
, bleibt das Array tatsächlich intakt, mit Ausnahme von Elementen, die die angegebene Bedingung in "cond"
nicht erfüllt haben werden aus dem Array entfernt. Da wir immer noch ein "Array" als Ausgabe haben, können wir dann den
Der $reduce
arbeitet dagegen die Array-Elemente durch und liefert über jedes Element einen Ausdruck und einen gespeicherten "Akkumulator"-Wert, den wir mit "initialValue"
initialisiert haben . In diesem Fall dasselbe $eq
Der Test wird innerhalb von $cond
angewendet
Operator. Dies ist ein "ternäres" oder if/then/else
Bedingungsoperator, der es einem getesteten Ausdruck ermöglicht, der einen booleschen Wert zurückgibt, um den then
zurückzugeben Wert, wenn true
oder das else
Wert, wenn false
.
In diesem Ausdruck geben wir 1
zurück oder 0
und liefern das Gesamtergebnis der Addition dieses zurückgegebenen Werts und des aktuellen "Akkumulators" "$$value"
mit dem $sum
Operator, um diese zu addieren.
Das endgültige Formular verwendete $unwind
auf dem Array. Was dies tatsächlich tut, ist die Array-Mitglieder zu dekonstruieren, um ein "neues Dokument" für jedes Array-Mitglied und seine zugehörigen übergeordneten Felder im Originaldokument zu erstellen. Dies "kopiert" effektiv das Hauptdokument für jedes Arraymitglied.
Sobald Sie $unwind
die Struktur der Dokumente wird in eine "flachere" Form geändert. Aus diesem Grund können Sie dann den nachfolgenden $match
Pipeline-Phase, um die nicht abgeglichenen Dokumente zu entfernen.
Dies bringt uns zu $group
die angewendet wird, um alle Informationen, die sich auf einen gemeinsamen Schlüssel beziehen, "wieder zusammenzubringen". In diesem Fall ist es die _id
-Feld des Originaldokuments, das natürlich in jedes vom $unwind
. Wenn wir zu diesem "gemeinsamen Schlüssel" als einzelnes Dokument zurückkehren, können wir die verbleibenden "Dokumente" "zählen", die aus dem Array extrahiert wurden, indem wir $sum
Akku.
Wenn wir das verbleibende „Array“ zurückhaben wollten, können Sie $push
und bauen Sie das Array nur mit den verbleibenden Mitgliedern neu auf:
{ "$group": {
"_id": "$_id",
"Array": { "$push": "$Array" },
"total": { "$sum": 1 }
}}
Aber natürlich anstatt $size
zu verwenden
in einer anderen Pipeline-Phase können wir einfach noch „zählen“, wie wir es bereits mit dem $summe