W przypadku MongoDB 3.6 i nowszych użyj struktury agregacji z $replaceRoot
potok, który można zastosować w połączeniu z $mergeObjects
operator jako newRoot
wyrażenie.
To wyrażenie
{ "$mergeObjects": ["$subdoc", "$$ROOT"] }
połączy pola najwyższego poziomu w dokumencie z polami osadzonymi w poddokumencie, więc na końcu Twoja agregacja będzie wyglądać następująco:
db.collection.aggregate([
{ "$replaceRoot": {
"newRoot": {
"$mergeObjects": [ "$subdoc", "$$ROOT" ]
}
} },
{ "$project": { "subdoc": 0 } }
])
W przeciwnym razie potrzebowałbyś mechanizmu, aby uzyskać wszystkie klucze dynamiczne potrzebne do złożenia dynamicznego $project
dokument. Jest to możliwe dzięki Map-Reduce
. Następująca operacja mapreduce spowoduje wypełnienie oddzielnej kolekcji wszystkimi kluczami jako _id
wartości:
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"
})
Aby uzyskać listę wszystkich kluczy dynamicznych, uruchom odrębnie w wynikowej kolekcji:
db[mr.result].distinct("_id")
["field2", "field3", ...]
Teraz, biorąc pod uwagę powyższą listę, możesz złożyć swój $project
dokument potoku agregacji, tworząc obiekt, który będzie miał swoje właściwości ustawione w pętli. Zwykle Twój $project
dokument będzie miał następującą strukturę:
var project = {
"$project": {
"field1": 1,
"field2": "$subdoc.field2",
"field3": "$subdoc.field3"
}
};
Korzystając z powyższej listy kluczy dokumentów podrzędnych, możesz dynamicznie skonstruować powyższe za pomocą reduce()
metoda:
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]);