Untuk MongoDB 3.6 dan yang lebih baru, gunakan kerangka kerja agregasi dengan $replaceRoot
pipeline yang dapat diterapkan bersama dengan $mergeObjects
operator sebagai newRoot
ekspresi.
Ungkapan ini
{ "$mergeObjects": ["$subdoc", "$$ROOT"] }
akan menggabungkan bidang tingkat atas dalam dokumen dengan bidang yang disematkan pada subdokumen sehingga pada akhirnya operasi agregat Anda akan menjadi sebagai berikut:
db.collection.aggregate([
{ "$replaceRoot": {
"newRoot": {
"$mergeObjects": [ "$subdoc", "$$ROOT" ]
}
} },
{ "$project": { "subdoc": 0 } }
])
Jika tidak, Anda akan memerlukan mekanisme untuk mendapatkan semua kunci dinamis yang Anda perlukan untuk merakit $project
dinamis dokumen. Ini dimungkinkan melalui Map-Reduce
. Operasi mapreduce berikut akan mengisi koleksi terpisah dengan semua kunci sebagai _id
nilai:
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"
})
Untuk mendapatkan daftar semua kunci dinamis, jalankan yang berbeda pada koleksi yang dihasilkan:
db[mr.result].distinct("_id")
["field2", "field3", ...]
Sekarang dengan daftar di atas, Anda dapat merakit $project
dokumen pipa agregasi dengan membuat objek yang propertinya akan diatur dalam satu lingkaran. Biasanya $project
. Anda dokumen akan memiliki struktur ini:
var project = {
"$project": {
"field1": 1,
"field2": "$subdoc.field2",
"field3": "$subdoc.field3"
}
};
Jadi dengan menggunakan daftar kunci subdokumen di atas, Anda dapat secara dinamis membuat subdokumen di atas menggunakan 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]);