O erro é porque não é mais uma matriz depois de
$unwind
e, portanto, não é mais um argumento válido para $size
. Você parece estar tentando "mesclar" algumas respostas existentes sem entender o que elas estão fazendo. O que você realmente quer aqui é
$filter
e $size
db.collection.aggregate([
{ "$project": {
"total": {
"$size": {
"$filter": {
"input": "$Array",
"cond": { "$eq": [ "$$this.field1", "a" ] }
}
}
}
}}
])
Ou "reinvente a roda" usando
$reduce
:db.collection.aggregate([
{ "$project": {
"total": {
"$reduce": {
"input": "$Array",
"initialValue": 0,
"in": {
"$sum": [
"$$value",
{ "$cond": [{ "$eq": [ "$$this.field1", "a" ] }, 1, 0] }
}
}
}
}}
])
Ou pelo que você estava tentando fazer com
$unwind
, você realmente $group
novamente para "contar" quantas partidas foram:db.collection.aggregate([
{ "$unwind": "$Array" },
{ "$match": { "Array.field1": "a" } },
{ "$group": {
"_id": "$_id",
"total": { "$sum": 1 }
}}
])
As duas primeiras formas são as "ótimas" para ambientes MongoDB modernos. O formulário final com
$unwind
e $group
é uma construção "legada" que realmente não é necessária para esse tipo de operação desde o MongoDB 2.6, embora com alguns operadores ligeiramente diferentes. Nesses dois primeiros estamos basicamente comparando o
field1
valor de cada elemento da matriz enquanto ainda é uma matriz. Ambos $filter
e $reduce
são operadores modernos projetados para trabalhar com uma matriz existente no local. A mesma comparação é feita em cada um usando a agregação $eq
operador que retorna um valor booleano baseado em se os argumentos fornecidos são "iguais" ou não. Neste caso, em cada membro da matriz para o valor esperado de "a"
. No caso de
$filter
, a matriz realmente permanece intacta, exceto por quaisquer elementos que não atendem à condição fornecida em "cond"
são removidos da matriz. Como ainda temos um "array" como saída, podemos usar o $size
operador para medir o número de elementos da matriz restantes depois que essa condição de filtro foi processada. O
$reduce
por outro lado, funciona através dos elementos da matriz e fornece uma expressão sobre cada elemento e um valor "acumulador" armazenado, que inicializamos com "initialValue"
. Nesse caso, o mesmo $eq
teste é aplicado dentro do $cond
operador. Este é um "ternário" ou if/then/else
operador condicional que permite que uma expressão testada que retorne um valor booleano retorne o então
valor quando true
ou o outro
valor quando falso
. Nessa expressão, retornamos
1
ou 0
respectivamente e forneça o resultado geral da adição desse valor retornado e o "acumulador" atual "$$value"
com o $sum
operador para adicioná-los juntos. O formulário final usado
$unwind
na matriz. O que isso realmente faz é desconstruir os membros da matriz para criar um "novo documento" para cada membro da matriz e seus campos pai relacionados no documento original. Isso efetivamente "copia" o documento principal para cada membro da matriz. Depois de
$unwind
a estrutura dos documentos é alterada para uma forma "mais plana". É por isso que você pode fazer o subsequente $match
estágio de pipeline para remover os documentos não correspondentes. Isso nos leva a
$group
que é aplicado para "reunir" todas as informações relacionadas a uma chave comum. Neste caso é o _id
campo do documento original, que obviamente foi copiado em todos os documentos produzidos pelo $unwind
. À medida que voltamos a essa "chave comum" como um único documento, podemos "contar" os "documentos" restantes extraídos do array usando o $sum
acumulador. Se quisermos o "array" restante de volta, você pode
$push
e reconstrua a matriz apenas com os membros restantes: { "$group": {
"_id": "$_id",
"Array": { "$push": "$Array" },
"total": { "$sum": 1 }
}}
Mas é claro que em vez de usar
$size
em outro estágio do pipeline, podemos simplesmente "contar" como já fizemos com o $soma