Błąd jest spowodowany tym, że nie jest to już tablica po $unwind
i dlatego nie jest już prawidłowym argumentem $size
.
Wygląda na to, że próbujesz „scalić” kilka istniejących odpowiedzi, nie rozumiejąc, co robią. To, czego naprawdę chcesz tutaj, to $filter
i $size
db.collection.aggregate([
{ "$project": {
"total": {
"$size": {
"$filter": {
"input": "$Array",
"cond": { "$eq": [ "$$this.field1", "a" ] }
}
}
}
}}
])
Lub „wymyśl na nowo koło” za pomocą $reduce
:
db.collection.aggregate([
{ "$project": {
"total": {
"$reduce": {
"input": "$Array",
"initialValue": 0,
"in": {
"$sum": [
"$$value",
{ "$cond": [{ "$eq": [ "$$this.field1", "a" ] }, 1, 0] }
}
}
}
}}
])
Lub za to, co próbowałeś zrobić z $unwind
, właściwie $group
ponownie, aby „policzyć”, ile było dopasowań:
db.collection.aggregate([
{ "$unwind": "$Array" },
{ "$match": { "Array.field1": "a" } },
{ "$group": {
"_id": "$_id",
"total": { "$sum": 1 }
}}
])
Pierwsze dwie formy są "optymalne" dla nowoczesnych środowisk MongoDB. Ostateczny formularz z $unwind
i $group
jest "starszą" konstrukcją, która tak naprawdę nie była potrzebna do tego typu operacji od MongoDB 2.6, chociaż z kilkoma nieco innymi operatorami.
W tych pierwszych dwóch po prostu porównujemy pole1
wartość każdego elementu tablicy, podczas gdy nadal jest to tablica. Oba $filter
i $reduce
to nowoczesne operatory zaprojektowane do pracy z istniejącą macierzą. To samo porównanie jest wykonywane na każdym z nich przy użyciu agregacji $eq
operator, który zwraca wartość logiczną na podstawie tego, czy podane argumenty są „równe”, czy nie. W tym przypadku na każdym elemencie tablicy do oczekiwanej wartości "a"
.
W przypadku $filter
, tablica pozostaje nienaruszona, z wyjątkiem elementów, które nie spełniły podanego warunku w "cond"
są usuwane z tablicy. Ponieważ nadal mamy „tablicę” jako dane wyjściowe, możemy użyć $rozmiar
operator do pomiaru liczby elementów tablicy pozostałych po przetworzeniu warunku filtra.
$reduce
z drugiej strony działa poprzez elementy tablicy i dostarcza wyrażenie nad każdym elementem oraz przechowywaną wartość "akumulatora", którą zainicjalizowaliśmy za pomocą "initialValue"
. W tym przypadku ten sam $eq
test jest stosowany w ramach $cond
operator. To jest „trójkąt” lub if/then/else
operator warunkowy, który umożliwia testowanemu wyrażeniu zwracającemu wartość logiczną zwrócenie then
wartość, gdy prawda
lub inne
wartość, gdy false
.
W tym wyrażeniu zwracamy 1
lub 0
odpowiednio i podaj ogólny wynik dodania tej zwróconej wartości i bieżącej "akumulatora" "$$value"
z $sum
operatora, aby dodać je razem.
Ostateczna forma użyta $unwind
na tablicy. To, co w rzeczywistości robi, to dekonstruuje elementy członkowskie tablicy, aby utworzyć „nowy dokument” dla każdego elementu członkowskiego tablicy i powiązanych z nim pól nadrzędnych w oryginalnym dokumencie. To skutecznie „kopiuje” główny dokument dla każdego członka tablicy.
Gdy $unwind
zmieniono strukturę dokumentów na bardziej „płaską”. Dlatego możesz wykonać kolejne $match
etap potoku, aby usunąć niedopasowane dokumenty.
To prowadzi nas do $group
który jest stosowany do "sprowadzenia" wszystkich informacji związanych ze wspólnym kluczem. W tym przypadku jest to _id
pole oryginalnego dokumentu, które oczywiście zostało skopiowane do każdego dokumentu wyprodukowanego przez $odpręż
. Wracając do tego „klucza wspólnego” jako pojedynczego dokumentu, możemy „policzyć” pozostałe „dokumenty” wyodrębnione z tablicy za pomocą $sum
akumulator.
Jeśli chcielibyśmy odzyskać pozostałą „tablicę”, możesz $push
i odbuduj tablicę tylko z pozostałymi członkami:
{ "$group": {
"_id": "$_id",
"Array": { "$push": "$Array" },
"total": { "$sum": 1 }
}}
Ale oczywiście zamiast używać $size
na innym etapie potoku możemy po prostu nadal „liczyć”, tak jak to zrobiliśmy już z $ suma