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

时间:2012-02-03 02:33:16

标签: arrays json mongodb rename

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

6 个答案:

答案 0 :(得分:40)

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

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()与未加密的集合一起使用。

答案 1 :(得分:16)

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

答案 2 :(得分:15)

我有类似的问题。在我的情况下,我发现以下内容更容易:

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

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

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

答案 3 :(得分:1)

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

答案 4 :(得分:1)

Mongo 4.2开始,db.collection.update()可以接受聚合管道,最后允许根据其自身值更新字段:

// { general: { files: { file: [
//   { version: { software_program: "MonkeyPlus", indentifier: "6.0.0" } }
// ] } } }
db.collection.update(
  {},
  [{ $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
           }
         }
       }
  }}}],
  { multi: true }
)
// { general: { files: { file: [
//   { version: { software_program: "MonkeyPlus", identifier: "6.0.0" } }
// ] } } }

从字面上看,update通过$set对其"general.files.file"元素$map a "file"设置in数组来"version" "software_program"对象包含相同的"identifier"字段和重命名的"indentifier"字段,其中包含曾经是{}的值。


一些其他详细信息:

  • 第一部分[{ $set: { "general.files.file": { ... }}}]是匹配查询,用于过滤要更新的文档(在本例中为所有文档)。

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

    • $set是新的聚合运算符,在这种情况下,它将替换"general.files.file"数组的值。
    • 使用$map操作,我们将"identifier"数组中的所有元素替换为基本上相同的元素,但使用"indentifier"字段而不是input
    • as是要映射的数组。
    • in是赋予循环元素的变量名称
    • "version"是应用于元素的实际转换。在这种情况下,它将用"software_program""identifier"字段组成的$$file.xxxx对象替换元素。通过使用file符号(其中as{ multi: true }部分中元素的名称)提取其先前的值来填充这些字段。
  • 不要忘记@Entity() export class Document { @PrimaryGeneratedColumn() id: number; @Column() name: string; @Column() path: string; ... } ,否则只会更新第一个匹配的文档。

答案 5 :(得分:0)

我的建议就是这个:

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