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

Arrays MongoDB重命名数组中的数据库字段,arrays,json,mongodb,rename,Arrays,Json,Mongodb,Rename,我需要在此重命名标识符: { "general" : { "files" : { "file" : [ { "version" : { "software_program" : "MonkeyPlus", "indentifier" : "6.0.0" } } ] } } } 我试过了 db.nrel.comp

我需要在此重命名
标识符

{ "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可能不是动态数组

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

尽管不得不这样做听起来很糟糕,但解决方案其实相当简单。这当然取决于你有多少记录。但以下是我的例子:

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()
函数。

我也遇到了类似的问题。在我的情况下,我发现以下几点要容易得多:

  • 我将集合导出为json:
  • 我使用我喜欢的文本编辑工具对json进行了查找和替换

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


  • 我还想重命名数组中的一个属性:我使用了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)  
    });
    

    启动
    Mongo 4.2
    ,可以接受聚合管道,最后允许根据字段自身的值更新字段:

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

    从字面上说,这个
    更新
    s文档的方法是(re)
    $set
    通过
    $map
    ping其
    “文件”
    元素
    “版本”
    对象中,包含相同的
    “软件程序”
    字段和重命名的
    “标识符”
    字段,其中包含过去是“标识符”值的内容。


    另外还有几个细节:

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

    • 第二部分是更新聚合管道(注意方括号表示使用聚合管道):

      • 是一个新的聚合运算符,在本例中,它将替换
        “general.files.file”
        数组的值
      • 使用一个操作,我们用基本相同的元素替换
        “general.files.file”
        数组中的所有元素,但使用
        “identifier”
        字段而不是
        “indicator”
      • input
        是要映射的数组
      • as
        是给定给循环元素的变量名
      • 中的
        是应用于元素的实际转换。在这种情况下,它用一个
        “version”
        对象替换元素,该对象由
        “software\u program”
        “identifier”
        字段组成。这些字段是通过使用
        $$file.xxxx
        符号提取它们以前的值来填充的(其中
        file
        是作为
        部分的
        元素的名称)

      • 我的建议是:

        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.
        ])
        
        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.
        ])
        
        但是,这仅在数组
        general.files.file
        只有一个文档时有效。很可能情况并非总是如此,那么您可以使用此选项:

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

        $rename
        不会扩展数组,@Alexander Azarov,有什么解决方法吗?我听说有人会复制到$rename可以进入的字段中…我个人正在编写脚本,遍历集合并进行迁移如果您希望使用数据库命令执行此操作:坚持使用MongoDB。。。这样的事情让我很难过:(我并不反对。我想这是相对容易实现的结果。我想这应该是公认的答案。我在几个收藏中使用了这种方法,每个收藏多达1200万份文档,效果非常好!绝对如此。这非常有效。遗憾的是MongoDB还不能在本机中包含这种行为。最好使用snapshot():
        db.Setting.find({'Value.Tiers.0.AssetUnderManagement':{$exists:1}}).snapshot().forEach(…)
        否则您可能会陷入无限循环。另请参阅我的新循环。感谢详细信息,@PatrycjaK!更新我的答案。@Andrew Samuelsen我认为这应该是选定的答案-一个解决“按设计”问题的脚本问题我有点怀疑这种方法在大数据集上的效果如何。假设我的数据库是5gb,这个过程听起来很慢。或者我没有使用正确的文本编辑工具=-}也要小心实时数据库。如果在执行这些步骤时添加/修改了记录,更改将丢失。如果您只有在笔记本电脑上运行,但如果您在生产环境中工作,这不是一个可行的解决方案。从MongoDB 4.0开始,您还可以添加if(b.hasOwnProperty(“xxx”))用于验证属性或数组是否存在。您需要手动保留
        软件\u程序
        。但如果版本字段有许多子字段,并且每个文档中可能有不同的字段,该怎么办?