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