Gebruik voor MongoDB 3.6 en nieuwer een aggregatieframework met een $replaceRoot
pijplijn die kan worden toegepast in combinatie met de $mergeObjects
operator als de newRoot
uitdrukking.
Deze uitdrukking
{ "$mergeObjects": ["$subdoc", "$$ROOT"] }
zal de velden op het hoogste niveau in het document samenvoegen met die in de ingesloten velden van het subdoc, zodat uw totale bewerking uiteindelijk als volgt zal zijn:
db.collection.aggregate([
{ "$replaceRoot": {
"newRoot": {
"$mergeObjects": [ "$subdoc", "$$ROOT" ]
}
} },
{ "$project": { "subdoc": 0 } }
])
Anders zou je een mechanisme nodig hebben om alle dynamische sleutels te krijgen die je nodig hebt om het dynamische $project
samen te stellen document. Dit is mogelijk via Map-Reduce
. De volgende mapreduce-bewerking zal een aparte verzameling vullen met alle sleutels als de _id
waarden:
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"
})
Om een lijst van alle dynamische sleutels te krijgen, voer je het volgende uit op de resulterende verzameling:
db[mr.result].distinct("_id")
["field2", "field3", ...]
Gezien de bovenstaande lijst, kunt u uw $project
. samenstellen aggregatiepijplijndocument door een object te maken waarvan de eigenschappen binnen een lus worden ingesteld. Normaal gesproken is uw $project
document heeft deze structuur:
var project = {
"$project": {
"field1": 1,
"field2": "$subdoc.field2",
"field3": "$subdoc.field3"
}
};
Dus met behulp van de bovenstaande lijst met subdocumentsleutels, kunt u het bovenstaande dynamisch construeren met behulp van JavaScript's reduce()
methode:
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]);