web-dev-qa-db-ja.com

配列内のMongoDB名前変更データベースフィールド

これで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

38

ドキュメントで述べたように、単一のコマンドで配列内のフィールドの名前を直接変更する方法はありません。唯一のオプションは、コレクションドキュメントを反復処理し、それらを読み取って、$ unset old/$ set new操作でそれぞれを更新することです。

20
Remon van Vliet

価値があることについては、やらなくてはならないように思えますが、ソリューションは実際にはかなり簡単です。もちろん、これはレコードの数によって異なります。しかし、これが私の例です:

_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()関数を削除する必要があります。

44
Eli Gassert

同様の問題がありました。私の状況では、次の方がはるかに簡単であることがわかりました。

  1. コレクションをjsonにエクスポートしました。
mongoexport --db mydb --collection modules --out modules.json
  1. 私は、お気に入りのテキスト編集ユーティリティを使用して、jsonで検索と置換を行いました。

  2. 編集したファイルを再インポートし、途中で古いコレクションを削除しました。

mongoimport --db mydb --collection modules --drop --file modules.json
19
fraccy

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" } }
// ] } } }

文字通り、このupdatesドキュメントは(re)$settingによって"general.files.file"配列を$mappingによって"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パーツから要素に付けられた名前です)。
8
Xavier Guihot

また、配列内のプロパティの名前を変更したいと思います。

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)  
});
5
Cedric Michel

私の提案はこれです:

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.
])
0