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

And*_*sen 35 arrays json rename mongodb

我需要重命名indentifier:

{ "general" : 
  { "files" : 
    { "file" : 
      [  
        {  "version" : 
          {  "software_program" : "MonkeyPlus",      
             "indentifier" : "6.0.0" 
          } 
        } 
      ] 
    } 
  } 
}
Run Code Online (Sandbox Code Playgroud)

我试过了

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

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

Eli*_*ert 42

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

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);
});
Run Code Online (Sandbox Code Playgroud)

我遍历我的集合,其中找到了数组并找到了"错误"的名称.然后我迭代子集合,设置新值,删除旧集合,并更新整个文档.这是相对无痛的.当然,我只有几万行可以搜索,其中只有几十行符合标准.

不过,我希望这个答案有助于某人!

编辑:添加snapshot()到查询中.在评论中查看原因.

在从数据库中检索任何文档之前,必须将snapshot()应用于游标.您只能将snapshot()与unsharded集合一起使用.

  • Imho这应该是公认的答案.我在几个集合中执行了这种方法,每个集合包含多达1200万个文档,它就像一个魅力! (3认同)
  • 绝对.这非常有效.可惜MongoDB本身还不能包含这种行为. (2认同)
  • 最好使用snapshot():`db.Setting.find({'Value.Tiers.0.AssetsUnderManagement':{$ exists:1}}).snapshot().forEach(...)`否则你可以结束在无限循环中.另见https://docs.mongodb.org/v3.0/reference/method/cursor.snapshot/ (2认同)

Rem*_*iet 18

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

  • 被MongoDB困住......这样的事让我伤心:( (15认同)

小智 18

我遇到了类似的问题.在我的情况下,我发现以下内容更容易:

  1. 我将集合导出到json:
mongoexport --db mydb --collection modules --out modules.json
Run Code Online (Sandbox Code Playgroud)
  1. 我使用我喜欢的文本编辑工具在json上进行了查找和替换.

  2. 我重新导入了编辑过的文件,一路上丢弃了旧的集合:

mongoimport --db mydb --collection modules --drop --file modules.json
Run Code Online (Sandbox Code Playgroud)

  • 对实时数据库也要谨慎.如果在执行这些步骤所需的时间内添加/修改记录,则更改将丢失. (3认同)
  • 我对这种方法对大型数据集的效果持怀疑态度.假设我的数据库是5GB,这个过程听起来很慢.或者我可能没有使用正确的文本编辑工具= - } (2认同)

Sud*_*ran 11

我不得不用相同的模式来面对这个问题。因此,此查询对于想要重命名嵌入数组中的字段的人很有帮助。

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" },
]);
Run Code Online (Sandbox Code Playgroud)

另一种解决方案


Ced*_*hel 7

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

  • [`snapshot` 已弃用](https://mongodb.github.io/node-mongodb-native/3.1/api/Cursor.html#snapshot) 从 MongoDB 4.0 开始。 (2认同)

Xav*_*hot 5

开始Mongo 4.2db.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" } }
// ] } } }
Run Code Online (Sandbox Code Playgroud)

从字面上看,这update是通过$set"general.files.file"数组的元素执行$mapping操作来重新整理数组的,该对象包含一个包含相同字段的对象和一个重命名的字段,该字段包含以前的值。"file"in"version""software_program""identifier""indentifier"


还有一些其他细节:

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

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

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

  • 您手动保存“软件程序”。但是,如果版本字段有很多子字段,并且每个文档中可能存在不同字段怎么办? (2认同)