これでindentifier
の名前を変更する必要があります:
{ "general" :
{ "files" :
{ "file" :
[
{ "version" :
{ "software_program" : "MonkeyPlus",
"indentifier" : "6.0.0"
}
}
]
}
}
}
私はもう試した
db.nrel.component.update(
{},
{ $rename: {
"general.files.file.$.version.indentifier" : "general.files.file.$.version.identifier"
} },
false, true
)
ただし、次を返します:$rename source may not be dynamic array
。
ドキュメントで述べたように、単一のコマンドで配列内のフィールドの名前を直接変更する方法はありません。唯一のオプションは、コレクションドキュメントを反復処理し、それらを読み取って、$ unset old/$ set new操作でそれぞれを更新することです。
価値があることについては、やらなくてはならないように思えますが、ソリューションは実際にはかなり簡単です。もちろん、これはレコードの数によって異なります。しかし、これが私の例です:
_db.Setting.find({ 'Value.Tiers.0.AssetsUnderManagement': { $exists: 1 } }).snapshot().forEach(function(item)
{
for(i = 0; i != item.Value.Tiers.length; ++i)
{
item.Value.Tiers[i].Aum = item.Value.Tiers[i].AssetsUnderManagement;
delete item.Value.Tiers[i].AssetsUnderManagement;
}
db.Setting.update({_id: item._id}, item);
});
_
配列が見つかり、「間違った」名前が見つかったコレクションを繰り返し処理します。次に、サブコレクションを反復処理し、新しい値を設定し、古い値を削除して、ドキュメント全体を更新します。それは比較的無痛でした。私が検索する行は数万行しかないのは当然ですが、そのうち数十行のみが基準を満たしています。
それでも、この答えが誰かを助けることを願っています!
編集:snapshot()
をクエリに追加しました。コメントでその理由をご覧ください。
データベースからドキュメントを取得する前に、カーソルにsnapshot()を適用する必要があります。シャーディングされていないコレクションでのみsnapshot()を使用できます。
MongoDB 3.4から、snapshot()関数が削除されました。Mongo3.4+を使用している場合、上記の例では、snapshot()関数を削除する必要があります。
同様の問題がありました。私の状況では、次の方がはるかに簡単であることがわかりました。
mongoexport --db mydb --collection modules --out modules.json
私は、お気に入りのテキスト編集ユーティリティを使用して、jsonで検索と置換を行いました。
編集したファイルを再インポートし、途中で古いコレクションを削除しました。
mongoimport --db mydb --collection modules --drop --file modules.json
Mongo 4.2
を開始すると、 db.collection.update()
は集計パイプラインを受け入れ、最終的に独自の値に基づいてフィールドの更新を許可できます。
// { general: { files: { file: [
// { version: { software_program: "MonkeyPlus", indentifier: "6.0.0" } }
// ] } } }
db.collection.updateMany(
{},
[{ $set: { "general.files.file": {
$map: {
input: "$general.files.file",
as: "file",
in: {
version: {
software_program: "$$file.version.software_program",
identifier: "$$file.version.indentifier" // fixing the typo here
}
}
}
}}}]
)
// { general: { files: { file: [
// { version: { software_program: "MonkeyPlus", identifier: "6.0.0" } }
// ] } } }
文字通り、このupdate
sドキュメントは(re)$set
tingによって"general.files.file"
配列を$map
pingによって"file"
要素in
同じ"version"
フィールドを含む"software_program"
オブジェクトと、値に使用されていたものを含む名前変更された"identifier"
フィールド"indentifier"
の。
いくつかの追加の詳細:
最初の部分{}
は一致クエリで、更新するドキュメント(この場合はすべてのドキュメント)をフィルタリングします。
2番目の部分[{ $set: { "general.files.file": { ... }}}]
は、更新集約パイプラインです(角括弧が集約パイプラインの使用を示すことに注意してください)。
$set
は、この場合に"general.files.file"
配列の値を置き換える新しい集計演算子です。$map
操作を使用して、"general.files.file"
配列のすべての要素を基本的に同じ要素で置き換えますが、"identifier"
ではなく"indentifier"
フィールドを使用します。input
はマップする配列です。as
は、ループ要素に付けられた変数名ですin
は、要素に適用される実際の変換です。この場合、要素は、"version"
フィールドと"software_program"
フィールドで構成される"identifier"
オブジェクトに置き換えられます。これらのフィールドは、$$file.xxxx
表記を使用して以前の値を抽出することにより入力されます(file
は、as
パーツから要素に付けられた名前です)。また、配列内のプロパティの名前を変更したいと思います。
db.getCollection('YourCollectionName').find({}).snapshot().forEach(function(a){
a.Array1.forEach(function(b){
b.Array2.forEach(function(c){
c.NewPropertyName = c.OldPropertyName;
delete c["OldPropertyName"];
});
});
db.getCollection('YourCollectionName').save(a)
});
私の提案はこれです:
db.nrel.component.aggregate([
{ $unwind: "$general.files.file" },
{
$set: {
"general.files.file.version.identifier": {
$ifNull: ["$general.files.file.version.indentifier", "$general.files.file.version.identifier"]
}
}
},
{ $unset: "general.files.file.version.indentifier" },
{ $set: { "general.files.file": ["$general.files.file"] } },
{ $out: "nrel.component" } // carefully - it replaces entire collection.
])
ただし、これは配列general.files.file
には単一のドキュメントのみがあります。ほとんどの場合これは常に当てはまるわけではなく、これを使用できます:
db.nrel.componen.aggregate([
{ $unwind: "$general.files.file" },
{
$set: {
"general.files.file.version.identifier": {
$ifNull: ["$general.files.file.version.indentifier", "$general.files.file.version.identifier"]
}
}
},
{ $unset: "general.files.file.version.indentifier" },
{ $group: { _id: "$_id", general_new: { $addToSet: "$general.files.file" } } },
{ $set: { "general.files.file": "$general_new" } },
{ $unset: "general_new" },
{ $out: "nrel.component" } // carefully - it replaces entire collection.
])