これは、mapReduce を使用して行うことができます。 :
ルートレベルでフィールド名だけを取得するには:
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 }});
これにより、次のように出力されます:
{
"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
}
フィールド名とその値の一部またはすべて(ドキュメント全体)を取得するには:
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 }});
これにより、次のように出力されます:
{
"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
}
サブドキュメントのフィールド名を取得するには(パスなし):
これを行うには、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])
});
}});
マップを次のように変更します:
function () {
getFields(this);
}
次に、db.loadServerScripts()
を実行します それらをロードします。
サブドキュメントのフィールド名を取得するには(パス付き):
以前のバージョンでは、フィールド名を返すだけで、それらを取得するためのパス全体ではありません。これは、キーの名前を変更する場合に必要になります。パスを取得するには:
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 + '.')
});
}});
マップを次のように変更します:
function () {
getFields(this, '');
}
重複するパスの一致を除外するには:
fkfoo.fkbar
フィールドがある場合は注意してください 、fkfoo
を返します およびfkfoo.fkbar
。パスの一致を重複させたくない場合は、次のようにします。
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);
});
}});
質問に戻り、これらのフィールドの名前を変更します:
この最後のオプションを使用すると、fk
で始まるキーを含むすべてのパスを取得できます 、したがって、 $rename
を使用できます。
そのために。
ただし、$rename
配列を含むものでは機能しないため、を使用できます。 forEach
更新を行います。 MongoDBの配列内のデータベースフィールドの名前変更
パフォーマンスノート:
MapReduceはそれほど速く考えられていないため、{ out: "fk_fields"}
を指定することをお勧めします。 結果をfk_fields
という新しいコレクションに出力します 後でそれらの結果をクエリしますが、それはユースケースによって異なります。
特定のケースで可能な最適化(一貫したスキーマ):
また、ドキュメントのスキーマが常に同じであることがわかっている場合は、そのうちの1つをチェックしてフィールドを取得するだけでよいので、limit: 1
を追加して行うことができます。 オプションオブジェクトに移動するか、findOne
アプリケーションレベルでそのフィールドを読み取ります。