Para MongoDB 3.6 y más reciente, use el marco de agregación con un $replaceRoot
canalización que se puede aplicar junto con $mergeObjects
operador como newRoot
expresión.
Esta expresión
{ "$mergeObjects": ["$subdoc", "$$ROOT"] }
combinará los campos de nivel superior en el documento con los de los campos incrustados del subdoc, por lo que al final su operación agregada será la siguiente:
db.collection.aggregate([
{ "$replaceRoot": {
"newRoot": {
"$mergeObjects": [ "$subdoc", "$$ROOT" ]
}
} },
{ "$project": { "subdoc": 0 } }
])
De lo contrario, necesitaría un mecanismo para obtener todas las claves dinámicas que necesita para ensamblar el $project
dinámico. documento. Esto es posible a través de Map-Reduce
. La siguiente operación mapreduce llenará una colección separada con todas las claves como _id
valores:
mr = db.runCommand({
"mapreduce": "my_collection",
"map" : function() {
for (var key in this.subdoc) { emit(key, null); }
},
"reduce" : function(key, stuff) { return null; },
"out": "my_collection" + "_keys"
})
Para obtener una lista de todas las claves dinámicas, ejecute distinto en la colección resultante:
db[mr.result].distinct("_id")
["field2", "field3", ...]
Ahora, dada la lista anterior, puede ensamblar su $project
documento de canalización de agregación mediante la creación de un objeto que tendrá sus propiedades establecidas dentro de un bucle. Normalmente tu $project
documento tendrá esta estructura:
var project = {
"$project": {
"field1": 1,
"field2": "$subdoc.field2",
"field3": "$subdoc.field3"
}
};
Entonces, al usar la lista anterior de claves de subdocumento, puede construir dinámicamente lo anterior usando JavaScript reduce()
método:
var subdocKeys = db[mr.result].distinct("_id"),
obj = subdocKeys.reduce(function (o, v){
o[v] = "$subdoc." + v;
return o;
}, { "field1": 1 }),
project = { "$project": obj };
db.collection.aggregate([project]);