sql >> Base de Datos >  >> NoSQL >> MongoDB

MongoDB:¿Contando cuántos elementos con un valor dado existen en una matriz, eso está en un documento?

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)