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

MongoDB:Contando quantos itens com um determinado valor existem em um array, que está em um documento?


A estrutura de agregação é ideal para isso. Considere executar o seguinte pipeline para obter o resultado desejado.
pipeline = [
    {
        "$match": {
            "name": "james",
            "books.year": 1990
        }
    },
    {
        "$project": {
            "numberOfBooks": {
                "$size": {                  
                    "$filter": {
                        "input": "$books",
                        "as": "el",
                        "cond": { "$eq": [ "$$el.year", 1990 ] }
                    }                   
                }
            }
        }
    }
];
db.collection.pipeline(pipeline);

O pipeline acima usa o novo $filter operador disponível para MongoDB 3.2 para produzir uma matriz que atende à condição especificada, ou seja, filtra elementos externos que não atendem aos critérios. A inicial $match pipeline é necessário para filtrar os documentos que entram no pipeline de agregação antecipadamente como uma estratégia de otimização de pipeline.

O $size O operador que aceita uma única expressão como argumento fornece o número de elementos na matriz resultante, portanto, você tem a contagem de livros desejada.

Para uma solução alternativa que não usa o $ filtro operador não encontrado em versões anteriores, considere a seguinte operação de pipeline:
pipeline = [
    {
        "$match": {
            "name": "james",
            "books.year": 1990
        }
    },
    {
        "$project": {
            "numberOfBooks": {
                "$size": {                  
                    "$setDifference": [
                        {
                            "$map": {
                                "input": "$books",
                                "as": "el",
                                "in": {
                                    "$cond": [
                                        { "$eq": [ "$$el.year", 1990 ] },
                                        "$$el",
                                        false
                                    ]
                                }
                            }
                        },
                        [false]
                    ]                   
                }
            }
        }
    }
];
db.collection.pipeline(pipeline);

O $project O estágio de pipeline envolve ajustar a matriz de livros para que você remova os documentos que não têm o ano de 1990. Isso é possível através do $setDifference e $map operadores.

O $map Essencialmente, o operador cria um novo campo de matriz que contém valores como resultado da lógica avaliada em uma subexpressão para cada elemento de uma matriz. O $setDifference operador então retorna um conjunto com elementos que aparecem no primeiro conjunto, mas não no segundo conjunto; isto é, realiza um complemento relativo do segundo conjunto em relação ao primeiro. Nesse caso, ele retornará a matriz de livros final que possui elementos com o ano de 1990 e, posteriormente, o $size calcula o número de elementos na matriz resultante, fornecendo assim a contagem de livros.

Para uma solução que usa o $descontrair operador, tendo em mente que (graças a esta resposta perspicaz de @BlakesSeven nos comentários):

e como último recurso, execute o seguinte pipeline:
pipeline = [
    {
        "$match": {
            "name": "james",
            "books.year": 1990
        }
    },
    { "$unwind": "$books" },
    {
        "$match": { "books.year": 1990 }
    },
    {
        "$group": {
            "_id": null
            "count": { "$sum": 1 }
        }
    }
]
db.collection.pipeline(pipeline)