Pour MongoDB 3.6 et versions ultérieures, utilisez le cadre d'agrégation avec un $replaceRoot
pipeline qui peut être appliqué conjointement avec le $mergeObjects
opérateur comme newRoot
expression.
Cette expression
{ "$mergeObjects": ["$subdoc", "$$ROOT"] }
fusionnera les champs de niveau supérieur du document avec ceux des champs incorporés du sous-doc. Ainsi, à la fin, votre opération d'agrégation sera la suivante :
db.collection.aggregate([
{ "$replaceRoot": {
"newRoot": {
"$mergeObjects": [ "$subdoc", "$$ROOT" ]
}
} },
{ "$project": { "subdoc": 0 } }
])
Sinon, vous auriez besoin d'un mécanisme pour obtenir toutes les clés dynamiques dont vous avez besoin pour assembler le $project
dynamique document. Ceci est possible grâce à Map-Reduce
. L'opération mapreduce suivante remplira une collection distincte avec toutes les clés en tant que _id
valeurs :
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"
})
Pour obtenir une liste de toutes les clés dynamiques, exécutez distinct sur la collection résultante :
db[mr.result].distinct("_id")
["field2", "field3", ...]
Maintenant, étant donné la liste ci-dessus, vous pouvez assembler votre $project
document de pipeline d'agrégation en créant un objet dont les propriétés seront définies dans une boucle. Normalement, votre $project
document aura cette structure :
var project = {
"$project": {
"field1": 1,
"field2": "$subdoc.field2",
"field3": "$subdoc.field3"
}
};
Ainsi, en utilisant la liste ci-dessus des clés de sous-document, vous pouvez construire dynamiquement ce qui précède en utilisant JavaScript reduce()
méthode :
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]);