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

Mongo:coincidencia donde la clave del objeto es variable

Con MongoDB 3.4.4, use el marco de agregación para consultar el documento. Esto es posible con $objectToArray operador que le permite asignar las claves en el campo procesado a una matriz de pares clave/valor. La lista será fácil de filtrar y obtener las claves que coincidan con cualquier condición que tenga.

En el siguiente ejemplo, la canalización de agregación consta de un campo adicional que contiene la(s) clave(s) que coinciden con la condición anterior de tener un valor falso, por lo que idealmente será una matriz:

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

que produce

{
    "_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"
    ]
}

Explicaciones

Comenzando con la expresión anidada

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

la entrada a $filter operator { "$objectToArray": "$processed" } convertirá las claves en el processed clave para esta matriz:

[ 
    {
        "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
    }
]

y $filter filtrará la matriz anterior para tener solo los elementos de objeto cuyo v la propiedad es NOT true :

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

$map luego devolverá una matriz asignada con solo los valores

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

entonces terminas con solo

[ "original" ]

como resultado.

Con versiones anteriores de MongoDB, será bastante difícil emitir consultas contra claves dinámicas. Considere modificar su esquema para seguir este modelo de documento que es más fácil de consultar:

// 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 }
    ]
}

Su consulta de búsqueda será simplemente

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

o use $map y $filter para devolver las claves con false valores como

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