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

MongoDB elemmatch múltiples elementos en matriz

No puede devolver varios elementos de una matriz que coincidan con sus criterios en ninguna forma de un .find() básico consulta. Para hacer coincidir más de un elemento, debe usar .aggregate() en su lugar.

La principal diferencia aquí es que la "consulta" hace exactamente lo que debe hacer y coincide con los "documentos" que cumplen con sus condiciones. Puedes intentar usar el $ posicional operador dentro de un argumento de proyección, pero las reglas allí son que solo coincidirá con el "primer" elemento de matriz que coincida con las condiciones de la consulta.

Para "filtrar" varios elementos de matriz, proceda de la siguiente manera:

db.sample.aggregate([
    // Filter possible documents
    { "$match": { "filtermetric.class": "s2" } },

    // Unwind the array to denormalize
    { "$unwind": "$filtermetric" },

    // Match specific array elements
    { "$match": { "filtermetric.class": "s2" } },

    // Group back to array form
    { "$group": {
        "_id": "$_id",
        "filtermetric": { "$push": "$filtermetric" }
    }}
])

En las versiones modernas de MongoDB que son la versión 2.6 o superior, puede hacer esto con $redact :

db.sample.aggregate([
    // Filter possible documents
    { "$match": { "filtermetric.class": "s2" } },

    // Redact the entries that do not match
    { "$redact": {
        "$cond": [
            { "$eq": [ { "$ifNull": [ "$class", "s2" ] }, "s2" ] },
            "$$DESCEND",
            "$$PRUNE"
        ]
    }}
])

Esa es probablemente su opción más eficiente, pero es recursiva, así que considere primero la estructura de su documento, ya que el mismo campo con nombre no puede existir con ninguna otra condición en ningún nivel.

Esta técnica con $map es posiblemente más segura, pero solo útil cuando los resultados en la matriz son "verdaderamente únicos". y $setDifference :

db.sample.aggregate([
    { "$project": {
        "filtermetric": { "$setDifference": [
            { "$map": [
                "input": "$filtermetric",
                "as": "el",
                "in": {"$cond": [
                    { "$eq": [ "$$el.class", "s2" ] },
                    "$$el",
                    false
                ]}
            ]},
            [false]
        ]}
    }}
])

También tenga en cuenta que tanto en el $group y $project Etapas de canalización operativa que necesita para especificar todos los campos que desea devolver en sus documentos de resultados de esa etapa.

La nota final es que $elemMatch no es necesario cuando solo está consultando el valor de una sola clave dentro de una matriz. Se prefiere y recomienda la "notación de puntos" cuando solo se accede a una sola clave de la matriz. $elemMatch solo debe ser necesario cuando las claves "múltiples" en el documento dentro de la matriz "elemento" deben coincidir con una condición de consulta.