简体   繁体   English

MongoDB重命名数组中的数据库字段

[英]MongoDB rename database field within array

I need to rename indentifier in this:我需要在此重命名indentifier

{ "general" : 
  { "files" : 
    { "file" : 
      [  
        {  "version" : 
          {  "software_program" : "MonkeyPlus",      
             "indentifier" : "6.0.0" 
          } 
        } 
      ] 
    } 
  } 
}

I've tried我试过了

db.nrel.component.update(
  {},
  { $rename: {
    "general.files.file.$.version.indentifier" : "general.files.file.$.version.identifier"
  } },
  false, true
)

but it returns: $rename source may not be dynamic array .但它返回: $rename source may not be dynamic array

For what it's worth, while it sounds awful to have to do, the solution is actually pretty easy.对于它的价值,虽然听起来很糟糕,但解决方案实际上非常简单。 This of course depends on how many records you have.这当然取决于你有多少记录。 But here's my example:但这是我的例子:

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);
});

I iterate over my collection where the array is found and the "wrong" name is found.我遍历了我的集合,其中找到了数组并找到了“错误”的名称。 I then iterate over the sub collection, set the new value, delete the old, and update the whole document.然后我遍历子集合,设置新值,删除旧值,并更新整个文档。 It was relatively painless.这是相对无痛的。 Granted I only have a few tens of thousands of rows to search through, of which only a few dozen meet the criteria.当然,我只有几万行要搜索,其中只有几十行符合条件。

Still, I hope this answer helps someone!不过,我希望这个答案对某人有所帮助!

Edit: Added snapshot() to the query.编辑:在查询中添加了snapshot() See why in the comments.在评论中查看原因。

You must apply snapshot() to the cursor before retrieving any documents from the database.在从数据库中检索任何文档之前,您必须将snapshot()应用于游标。 You can only use snapshot() with unsharded collections.您只能将snapshot()与非分片集合一起使用。

From MongoDB 3.4, snapshot() function was removed.从 MongoDB 3.4 中删除了snapshot()函数。 So if using Mongo 3.4+ ,the example above should remove snapshot() function.所以如果使用 Mongo 3.4+,上面的例子应该去掉snapshot()函数。

As mentioned in the documentation there is no way to directly rename fields within arrays with a single command.如文档中所述,无法使用单个命令直接重命名数组中的字段。 Your only option is to iterate over your collection documents, read them and update each with $unset old/ $set new operations.您唯一的选择是遍历您的集合文档,阅读它们并使用$unset old/ $set new 操作更新每个文档。

I had a similar problem.我有一个类似的问题。 In my situation I found the following was much easier:在我的情况下,我发现以下内容要容易得多:

  1. I exported the collection to json:我将集合导出到 json:
mongoexport --db mydb --collection modules --out modules.json
  1. I did a find and replace on the json using my favoured text editing utility.我使用我喜欢的文本编辑实用程序对 json 进行了查找和替换。

  2. I reimported the edited file, dropping the old collection along the way:我重新导入了编辑过的文件,同时删除了旧集合:

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

Starting Mongo 4.2 , db.collection.update() can accept an aggregation pipeline, finally allowing the update of a field based on its own value: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" } }
// ] } } }

Literally, this update s documents by (re) $set ting the "general.files.file" array by $map ping its "file" elements in a "version" object containing the same "software_program" field and the renamed "identifier" field which contains what used to be the value of "indentifier" .从字面上看,此update的文档通过(重新) $set "general.files.file"数组,通过$map in包含相同"software_program"字段和重命名的"identifier""version"对象中 ping 其"file"元素包含曾经是"indentifier"值的字段。


A couple additional details:一些额外的细节:

  • The first part {} is the match query, filtering which documents to update (in this case all documents).第一部分{}是匹配查询,过滤要更新的文档(在本例中为所有文档)。

  • The second part [{ $set: { "general.files.file": { ... }}}] is the update aggregation pipeline (note the squared brackets signifying the use of an aggregation pipeline):第二部分[{ $set: { "general.files.file": { ... }}}]是更新聚合管道(注意方括号表示使用聚合管道):

    • $set is a new aggregation operator which in this case replaces the value of the "general.files.file" array. $set是一个新的聚合运算符,在这种情况下它替换了"general.files.file"数组的值。
    • Using a $map operation, we replace all elements from the "general.files.file" array by basically the same elements, but with an "identifier" field rather than "indentifier" :使用$map操作,我们将"general.files.file"数组中的所有元素替换为基本相同的元素,但使用"identifier"字段而不是"indentifier"
    • input is the array to map. input是要映射的数组。
    • as is the variable name given to looped elements as
    • in is the actual transformation applied on elements. in是应用于元素的实际转换。 In this case, it replaces elements by a "version" object composed by a "software_program" and a "identifier" fields.在这种情况下,它将元素替换为由"software_program""identifier"字段组成的"version"对象。 These fields are populated by extracting their previous values using the $$file.xxxx notation (where file is the name given to elements from the as part).这些字段是通过使用$$file.xxxx表示法提取它们以前的值来填充的(其中fileas部分中的元素提供的名称)。

I had to face the issue with the same schema.我不得不面对相同架构的问题。 So this query will helpful for someone who wants to rename the field in an embedded array.因此,此查询对于想要重命名嵌入式数组中的字段的人会有所帮助。

db.getCollection("sampledocument").updateMany({}, [
  {
    $set: {
      "general.files.file": {
        $map: {
          input: "$general.files.file",
          in: {
            version: {
              $mergeObjects: [
                "$$this.version",
                { identifer: "$$this.version.indentifier" },
              ],
            },
          },
        },
      },
    },
  },
  { $unset: "general.files.file.version.indentifier" },
]);

Another Solution 另一种解决方案

I also would like rename a property in array: and I used thaht我也想重命名数组中的属性:我用过

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)  
});

The easiest and shortest solution using aggregate (Mongo 4.0+).使用聚合(Mongo 4.0+)的最简单和最短的解决方案。

db.myCollection.aggregate([
  {
    $addFields: {
      "myArray.newField": {$arrayElemAt: ["$myArray.oldField", 0] }
    }
  },
  {$project: { "myArray.oldField": false}},
  {$out: {db: "myDb", coll: "myCollection"}}
])

The problem using forEach loop as mention above is the very bad performance when the collection is huge.上面提到的使用 forEach 循环的问题是当集合很大时性能非常差。

My proposal would be this one:我的建议是这样的:

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

However, this works only when array general.files.file has a single document only.但是,这只适用于数组general.files.file只有一个文档时。 Most likely this will not always be the case, then you can use this one:很可能并非总是如此,那么您可以使用这个:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM