MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

MongoDB elemmatch plusieurs éléments dans le tableau

Vous ne pouvez pas renvoyer plusieurs éléments d'un tableau correspondant à vos critères sous aucune forme de base .find() requête. Pour faire correspondre plus d'un élément, vous devez utiliser le .aggregate() méthode à la place.

La principale différence ici est que la "requête" fait exactement ce qu'elle est censée faire et correspond aux "documents" qui répondent à vos conditions. Vous pouvez essayer d'utiliser le positionnel $ opérateur dans un argument de projection, mais les règles sont qu'il ne correspondra qu'au "premier" élément de tableau qui correspond aux conditions de la requête.

Afin de "filtrer" plusieurs éléments de tableau, procédez comme suit :

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" }
    }}
])

Dans les versions modernes de MongoDB qui sont la version 2.6 ou supérieure, vous pouvez le faire avec $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"
        ]
    }}
])

C'est probablement votre option la plus efficace, mais elle est récursive, donc considérez d'abord la structure de votre document car le même champ nommé ne peut exister avec aucune autre condition à n'importe quel niveau.

Cette technique avec $map est peut-être plus sûre mais seulement utile lorsque les résultats dans le tableau sont "vraiment uniques" et $setDifference :

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

Notez également que dans les deux $group et $project les étapes du pipeline opérationnel dont vous avez besoin pour spécifier tous les champs que vous avez l'intention de renvoyer dans vos documents de résultat à partir de cette étape.

La note finale est que $elemMatch n'est pas nécessaire lorsque vous n'interrogez que la valeur d'une seule clé dans un tableau. La "notation par points" est préférable et recommandée lors de l'accès à une seule clé du tableau. $elemMatch ne devrait être nécessaire que lorsque "plusieurs" clés dans le document dans le tableau "élément" doivent correspondre à une condition de requête.