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

Elemmatch do MongoDB vários elementos na matriz


Você não pode retornar vários elementos de uma matriz que correspondam aos seus critérios em qualquer forma de um .find() básico inquerir. Para corresponder a mais de um elemento, você precisa usar o .aggregate() método em vez disso.

A principal diferença aqui é que a "consulta" faz exatamente o que se destina a fazer e corresponde aos "documentos" que atendem às suas condições. Você pode tentar usar o $ posicional operador dentro de um argumento de projeção, mas as regras são que ele corresponderá apenas ao "primeiro" elemento da matriz que corresponde às condições da consulta.

Para "filtrar" vários elementos do array, proceda da seguinte forma:
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" }
    }}
])

Nas versões modernas do MongoDB que são a versão 2.6 ou superior, você pode fazer isso com $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"
        ]
    }}
])

Essa é provavelmente sua opção mais eficiente, mas é recursiva, portanto, considere primeiro a estrutura do seu documento, pois o mesmo campo nomeado não pode existir com nenhuma outra condição em nenhum nível.

Possivelmente mais seguro, mas útil apenas onde os resultados na matriz são "verdadeiramente exclusivos" é essa técnica com $map e $setDifference :
db.sample.aggregate([
    { "$project": {
        "filtermetric": { "$setDifference": [
            { "$map": [
                "input": "$filtermetric",
                "as": "el",
                "in": {"$cond": [
                    { "$eq": [ "$$el.class", "s2" ] },
                    "$$el",
                    false
                ]}
            ]},
            [false]
        ]}
    }}
])

Observando também que tanto no $group e $project estágios de pipeline operacionais que você precisa para especificar todos os campos que você pretende retornar em seus documentos de resultados desse estágio.

A nota final é que $elemMatch não é necessário quando você está apenas consultando o valor de uma única chave em uma matriz. A "notação de ponto" é preferida e recomendada ao acessar apenas uma única chave da matriz. $elemMatch só deve ser necessário quando "múltiplas" chaves no documento dentro da matriz "elemento" precisam corresponder a uma condição de consulta.