MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Condição de correspondência de membros da matriz de contagem agregada


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