Anda dapat melakukannya menggunakan mapReduce :
Untuk mendapatkan nama bidang saja di tingkat akar:
db.collection.mapReduce(function () {
Object.keys(this).map(function(key) {
if (key.match(/^fk/)) emit(key, null);
// OR: key.indexOf("fk") === 0
});
}, function(/* key, values */) {
// No need for params or to return anything in the
// reduce, just pass an empty function.
}, { out: { inline: 1 }});
Ini akan menampilkan sesuatu seperti ini:
{
"results": [{
"_id": "fkKey1",
"value": null
}, {
"_id": "fkKey2",
"value": null
}, {
"_id": "fkKey3",
"value": null
}],
"timeMillis": W,
"counts": {
"input": X,
"emit": Y,
"reduce": Z,
"output": 3
},
"ok" : 1
}
Untuk mendapatkan nama bidang dan salah satu atau semua (seluruh dokumen) nilainya:
db.test.mapReduce(function () {
var obj = this;
Object.keys(this).map(function(key) {
// With `obj[key]` you will get the value of the field as well.
// You can change `obj[key]` for:
// - `obj` to return the whole document.
// - `obj._id` (or any other field) to return its value.
if (key.match(/^fk/)) emit(key, obj[key]);
});
}, function(key, values) {
// We can't return values or an array directly yet:
return { values: values };
}, { out: { inline: 1 }});
Ini akan menampilkan sesuatu seperti ini:
{
"results": [{
"_id": "fkKey1",
"value": {
"values": [1, 4, 6]
}
}, {
"_id": "fkKey2",
"value": {
"values": ["foo", "bar"]
}
}],
"timeMillis": W,
"counts": {
"input": X,
"emit": Y,
"reduce": Z,
"output": 2
},
"ok" : 1
}
Untuk mendapatkan nama bidang dalam subdokumen (tanpa jalur):
Untuk melakukannya, Anda harus menggunakan store JavaScript functions on the Server
:
db.system.js.save({ _id: "hasChildren", value: function(obj) {
return typeof obj === "object";
}});
db.system.js.save({ _id: "getFields", value: function(doc) {
Object.keys(doc).map(function(key) {
if (key.match(/^fk/)) emit(key, null);
if (hasChildren(doc[key])) getFields(doc[key])
});
}});
Dan ubah peta Anda menjadi:
function () {
getFields(this);
}
Sekarang jalankan db.loadServerScripts()
untuk memuatnya.
Untuk mendapatkan nama bidang di subdokumen (dengan jalur):
Versi sebelumnya hanya akan mengembalikan nama bidang, bukan seluruh jalur untuk mendapatkannya, yang akan Anda perlukan jika yang ingin Anda lakukan adalah mengganti nama kunci tersebut. Untuk mendapatkan jalur:
db.system.js.save({ _id: "getFields", value: function(doc, prefix) {
Object.keys(doc).map(function(key) {
if (key.match(/^fk/)) emit(prefix + key, null);
if (hasChildren(doc[key]))
getFields(doc[key], prefix + key + '.')
});
}});
Dan ubah peta Anda menjadi:
function () {
getFields(this, '');
}
Untuk mengecualikan kecocokan jalur yang tumpang tindih:
Perhatikan bahwa jika Anda memiliki bidang fkfoo.fkbar
, itu akan mengembalikan fkfoo
dan fkfoo.fkbar
. Jika Anda tidak ingin kecocokan jalur yang tumpang tindih, maka:
db.system.js.save({ _id: "getFields", value: function(doc, prefix) {
Object.keys(doc).map(function(key) {
if (hasChildren(doc[key]))
getFields(doc[key], prefix + key + '.')
else if (key.match(/^fk/)) emit(prefix + key, null);
});
}});
Kembali ke pertanyaan Anda, mengganti nama bidang tersebut:
Dengan opsi terakhir ini, Anda mendapatkan semua jalur yang menyertakan kunci yang dimulai dengan fk
, sehingga Anda dapat menggunakan $rename
untuk itu.
Namun, $rename
tidak berfungsi untuk yang berisi array, jadi bagi yang Anda dapat menggunakan forEach
untuk melakukan pembaruan. Lihat MongoDB mengganti nama bidang basis data dalam larik
Catatan kinerja:
MapReduce tidak terlalu dipikirkan dengan cepat, jadi Anda mungkin ingin menentukan { out: "fk_fields"}
untuk menampilkan hasilnya ke dalam koleksi baru yang disebut fk_fields
dan kueri hasil tersebut nanti, tetapi itu akan bergantung pada kasus penggunaan Anda.
Pengoptimalan yang memungkinkan untuk kasus tertentu (skema yang konsisten):
Juga, perhatikan bahwa jika Anda tahu bahwa skema dokumen Anda selalu sama, maka Anda hanya perlu memeriksa salah satunya untuk mendapatkan bidangnya, sehingga Anda dapat melakukannya dengan menambahkan limit: 1
ke objek opsi atau hanya mengambil satu dokumen dengan findOne
dan membaca bidangnya di tingkat aplikasi.