L'errore è dovuto al fatto che non è più un array dopo che $unwind
e quindi non è più un argomento valido per $size
.
Sembra che tu stia tentando di "unire" un paio di risposte esistenti senza capire cosa stanno facendo. Quello che vuoi veramente qui è $filter
e $size
db.collection.aggregate([
{ "$project": {
"total": {
"$size": {
"$filter": {
"input": "$Array",
"cond": { "$eq": [ "$$this.field1", "a" ] }
}
}
}
}}
])
Oppure "reinventare la ruota" utilizzando $reduce
:
db.collection.aggregate([
{ "$project": {
"total": {
"$reduce": {
"input": "$Array",
"initialValue": 0,
"in": {
"$sum": [
"$$value",
{ "$cond": [{ "$eq": [ "$$this.field1", "a" ] }, 1, 0] }
}
}
}
}}
])
O per quello che stavi cercando di fare con $unwind
, in realtà $group
ancora per "contare" quante partite ci sono state:
db.collection.aggregate([
{ "$unwind": "$Array" },
{ "$match": { "Array.field1": "a" } },
{ "$group": {
"_id": "$_id",
"total": { "$sum": 1 }
}}
])
Le prime due forme sono "ottimali" per i moderni ambienti MongoDB. Il modulo finale con $unwind
e $group
è un costrutto "legacy" che in realtà non è stato necessario per questo tipo di operazioni da MongoDB 2.6, sebbene con alcuni operatori leggermente diversi.
In questi primi due stiamo fondamentalmente confrontando il field1
valore di ogni elemento dell'array mentre è ancora un array. Entrambi $filter
e $reduce
sono operatori moderni progettati per funzionare con un array esistente. Lo stesso confronto viene eseguito su ciascuno utilizzando l'aggregazione $eq
operatore che restituisce un valore booleano in base al fatto che gli argomenti forniti siano "uguali" o meno. In questo caso su ogni membro dell'array al valore previsto di "a"
.
Nel caso di $filter
, l'array rimane effettivamente intatto ad eccezione di eventuali elementi che non soddisfano la condizione fornita in "cond"
vengono rimossi dall'array. Dal momento che abbiamo ancora un "array" come output, possiamo quindi utilizzare $size
per misurare il numero di elementi dell'array rimasti dopo l'elaborazione di tale condizione di filtro.
Il $reduce
d'altra parte lavora attraverso gli elementi dell'array e fornisce un'espressione su ciascun elemento e un valore "accumulatore" memorizzato, che abbiamo inizializzato con "initialValue"
. In questo caso lo stesso $eq
il test viene applicato all'interno di $cond
operatore. Questo è un "ternario" o if/then/else
operatore condizionale che consente a un'espressione testata che restituisce un valore booleano di restituire then
valore quando true
o l'else
valore quando false
.
In quell'espressione restituiamo 1
o 0
rispettivamente e fornire il risultato complessivo dell'aggiunta di quel valore restituito e dell'attuale "accumulatore" "$$value"
con $sum
operatore per sommarli.
Il modulo finale ha utilizzato $unwind
sulla matrice. Ciò che in realtà fa è decostruire i membri dell'array per creare un "nuovo documento" per ogni membro dell'array e i relativi campi padre nel documento originale. Questo effettivamente "copia" il documento principale per ogni membro dell'array.
Una volta $unwind
la struttura dei documenti viene modificata in una forma "più piatta". Questo è il motivo per cui puoi quindi eseguire il successivo $match
fase di pipeline per rimuovere i documenti non corrispondenti.
Questo ci porta a $group
che viene applicato per "riunire" tutte le informazioni relative a una chiave comune. In questo caso è il _id
campo del documento originale, che è stato ovviamente copiato in ogni documento prodotto da $unwind
. Tornando a questa "chiave comune" come un unico documento, possiamo "contare" i restanti "documenti" estratti dall'array utilizzando $sum
accumulatore.
Se volessimo indietro l'"array" rimanente, puoi $push
e ricostruisci l'array con solo i membri rimanenti:
{ "$group": {
"_id": "$_id",
"Array": { "$push": "$Array" },
"total": { "$sum": 1 }
}}
Ma ovviamente invece di usare $size
in un'altra fase della pipeline, possiamo semplicemente "contare" come abbiamo già fatto con $sum