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

Mongo - Correspondance où la clé d'objet est variable

Avec MongoDB 3.4.4, utilisez le framework d'agrégation pour interroger le document. Ceci est rendu possible avec le $objectToArray qui vous permet de mapper les clés du champ traité sur un tableau de paires clé/valeur. La liste sera facile à filtrer et à obtenir la ou les clés correspondant à la condition que vous avez.

Dans l'exemple suivant, le pipeline d'agrégation se compose d'un champ supplémentaire qui contient la ou les clés qui correspondent à la condition ci-dessus d'avoir une valeur fausse, donc idéalement ce sera un tableau :

db.collection.aggregate([
    { "$addFields": {
        "notProcessed": { 
            "$map" : {
                "input": {
                    "$filter": {
                        "input": { "$objectToArray": "$processed" },
                        "as": "el",
                        "cond": { "$not": "$$el.v" }
                    }
                },
                "in": "$$this.k"
            }
        }
    } }
])

qui donne

{
    "_id" : ObjectId("5501b1648ef0b4eccc41814e"),
    "link" : "xxxxx.jpg",
    "processed" : {
        "320" : true,
        "480" : true,
        "540" : true,
        "720" : true,
        "800" : true,
        "1080" : true,
        "original" : false,
        "iPhone" : true
    },
    "notProcessed" : [ 
        "original"
    ]
}

Explications

En commençant par l'expression imbriquée

{
    "$filter": {
        "input": { "$objectToArray": "$processed" },
        "as": "el",
        "cond": { "$not": "$$el.v" }
    }
}

l'entrée de $filter opérateur { "$objectToArray": "$processed" } convertira les clés dans le processed clé de ce tableau :

[ 
    {
        "k" : "320",
        "v" : true
    }, 
    {
        "k" : "480",
        "v" : true
    }, 
    {
        "k" : "540",
        "v" : true
    }, 
    {
        "k" : "720",
        "v" : true
    }, 
    {
        "k" : "800",
        "v" : true
    }, 
    {
        "k" : "1080",
        "v" : true
    }, 
    {
        "k" : "original",
        "v" : false
    }, 
    {
        "k" : "iPhone",
        "v" : true
    }
]

et $filter filtrera le tableau ci-dessus pour n'avoir que les éléments d'objet dont v la propriété est NOT true :

[ 
    {
        "k" : "original",
        "v" : false
    }
]

$map renverra alors un tableau mappé avec uniquement les valeurs

[ { "k" : "original", "v" : false } ] => [ "original" ]

donc vous vous retrouvez avec juste

[ "original" ]

en conséquence.

Avec les anciennes versions de MongoDB, il sera assez difficile d'émettre des requêtes sur des clés dynamiques. Envisagez de modifier votre schéma pour suivre ce modèle de document qui est plus facile à interroger :

// this operation changes the schema
var processed = [];
db.collection.find().forEach( function(doc) {
     for(key in doc.processed) {
        if(doc.processed.hasOwnProperty(key)) {
            var item = { key: key, value: doc.processed[key] }
            processed.push(item);            
        }
     }
     doc.processed = processed;
     db.collection.save(doc);
});

// modified schema    

{ 
    "link": "xxxxx.jpg"
    "_id": ObjectId("5501b1648ef0b4eccc41814e"),
    "processed": [
         { "key": "320", "value": true },
         { "key": "480", "value": true },
         { "key": "540", "value": true },
         { "key": "720", "value": true },
         { "key": "800", "value": true },
         { "key": "1080", "value": true },
         { "key": "original", "value": false },
         { "key": "iPhone", "value": true }
    ]
}

Votre requête de recherche sera simplement

db.collection.find({"processed.value": false});

ou utilisez $map et $filter pour renvoyer les clés avec false valeurs comme

db.collection.aggregate([
    { "$project": {
        "link": 1,
        "notProcessed": { 
            "$map" : {
                "input": {
                    "$filter": {
                        "input": "$processed",
                        "as": "el",
                        "cond": { "$not": "$$el.v" }
                    }
                },
                "in": "$$this.k"
            }
        }
    } }
])