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)