For MongoDB 3.6 og nyere skal du bruge aggregeringsramme med en $replaceRoot
pipeline, der kan anvendes i forbindelse med $mergeObjects
operator som newRoot
udtryk.
Dette udtryk
{ "$mergeObjects": ["$subdoc", "$$ROOT"] }
vil flette felterne på øverste niveau i dokumentet med dem i de indlejrede underdoc-felter, så din samlede operation i sidste ende vil være som følger:
db.collection.aggregate([
{ "$replaceRoot": {
"newRoot": {
"$mergeObjects": [ "$subdoc", "$$ROOT" ]
}
} },
{ "$project": { "subdoc": 0 } }
])
Ellers ville du have brug for en mekanisme til at få alle de dynamiske nøgler, du skal bruge for at samle det dynamiske $project
dokument. Dette er muligt gennem Map-Reduce
. Den følgende mapreduce-operation vil udfylde en separat samling med alle nøglerne som _id
værdier:
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"
})
For at få en liste over alle de dynamiske nøgler skal du køre distinkt på den resulterende samling:
db[mr.result].distinct("_id")
["field2", "field3", ...]
Nu givet listen ovenfor, kan du samle dit $project
aggregeringspipelinedokument ved at skabe et objekt, der vil have dets egenskaber indstillet i en loop. Normalt dit $project
dokument vil have denne struktur:
var project = {
"$project": {
"field1": 1,
"field2": "$subdoc.field2",
"field3": "$subdoc.field3"
}
};
Så ved at bruge ovenstående liste over underdokumentnøgler kan du dynamisk konstruere ovenstående ved hjælp af JavaScripts reduce()
metode:
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]);