繁体   English   中英

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

[英]MongoDB rename database field within array

我需要在此重命名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

对于它的价值,虽然听起来很糟糕,但解决方案实际上非常简单。 这当然取决于你有多少记录。 但这是我的例子:

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()函数。 所以如果使用 Mongo 3.4+,上面的例子应该去掉snapshot()函数。

如文档中所述,无法使用单个命令直接重命名数组中的字段。 您唯一的选择是遍历您的集合文档,阅读它们并使用$unset old/ $set new 操作更新每个文档。

我有一个类似的问题。 在我的情况下,我发现以下内容要容易得多:

  1. 我将集合导出到 json:
mongoexport --db mydb --collection modules --out modules.json
  1. 我使用我喜欢的文本编辑实用程序对 json 进行了查找和替换。

  2. 我重新导入了编辑过的文件,同时删除了旧集合:

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的文档通过(重新) $set "general.files.file"数组,通过$map in包含相同"software_program"字段和重命名的"identifier""version"对象中 ping 其"file"元素包含曾经是"indentifier"值的字段。


一些额外的细节:

  • 第一部分{}是匹配查询,过滤要更新的文档(在本例中为所有文档)。

  • 第二部分[{ $set: { "general.files.file": { ... }}}]是更新聚合管道(注意方括号表示使用聚合管道):

    • $set是一个新的聚合运算符,在这种情况下它替换了"general.files.file"数组的值。
    • 使用$map操作,我们将"general.files.file"数组中的所有元素替换为基本相同的元素,但使用"identifier"字段而不是"indentifier"
    • input是要映射的数组。
    • as
    • in是应用于元素的实际转换。 在这种情况下,它将元素替换为由"software_program""identifier"字段组成的"version"对象。 这些字段是通过使用$$file.xxxx表示法提取它们以前的值来填充的(其中fileas部分中的元素提供的名称)。

我不得不面对相同架构的问题。 因此,此查询对于想要重命名嵌入式数组中的字段的人会有所帮助。

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" },
]);

另一种解决方案

我也想重命名数组中的属性:我用过

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

使用聚合(Mongo 4.0+)的最简单和最短的解决方案。

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

上面提到的使用 forEach 循环的问题是当集合很大时性能非常差。

我的建议是这样的:

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

暂无
暂无

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

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