El marco de agregación es ideal para tales. Considere ejecutar la siguiente canalización para obtener el resultado deseado.
pipeline = [
{
"$match": {
"name": "james",
"books.year": 1990
}
},
{
"$project": {
"numberOfBooks": {
"$size": {
"$filter": {
"input": "$books",
"as": "el",
"cond": { "$eq": [ "$$el.year", 1990 ] }
}
}
}
}
}
];
db.collection.pipeline(pipeline);
La canalización anterior utiliza el nuevo $filter
operador disponible para MongoDB 3.2 para producir una matriz que cumpla con la condición especificada, es decir, filtra los elementos externos que no cumplen los criterios. El $match
La canalización es necesaria para filtrar los documentos que ingresan a la canalización de agregación de manera temprana como una estrategia de optimización de la canalización.
El $size
operador que acepta una sola expresión como argumento y luego le da la cantidad de elementos en la matriz resultante, por lo que tiene el número de libros deseado.
Para una solución alternativa que no utiliza el $filter
operador no encontrado en versiones anteriores, considere la siguiente operación de canalización:
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);
El $project
La etapa de canalización implica ajustar la matriz de libros para que elimine los documentos que no tienen el año 1990. Esto es posible a través de $setDifference
y $map
operadores.
El $map
En esencia, el operador crea un nuevo campo de matriz que contiene valores como resultado de la lógica evaluada en una subexpresión para cada elemento de una matriz. El $setDifference
el operador luego devuelve un conjunto con elementos que aparecen en el primer conjunto pero no en el segundo conjunto; es decir, realiza un complemento relativo del segundo conjunto en relación con el primero. En este caso, devolverá la matriz de libros final que tiene elementos con el año 1990 y, posteriormente, el $size
calcula la cantidad de elementos en la matriz resultante, lo que le brinda el recuento de libros.
Para una solución que utiliza el $unwind
operador, teniendo en cuenta que (gracias a esta perspicaz respuesta de @BlakesSeven en los comentarios):
y como último recurso, ejecute la siguiente canalización:
pipeline = [
{
"$match": {
"name": "james",
"books.year": 1990
}
},
{ "$unwind": "$books" },
{
"$match": { "books.year": 1990 }
},
{
"$group": {
"_id": null
"count": { "$sum": 1 }
}
}
]
db.collection.pipeline(pipeline)