【问题标题】:Mongodb convert multiple objects to an array, in place, permanentlyMongodb将多个对象转换为数组,就地,永久
【发布时间】:2018-06-20 23:48:29
【问题描述】:

我有一个包含这种形式的文档的集合:

{
    "name" : "John Smith",    
    "store_affiliation" : {
        "stores" : {
            "ABCD" : {
                "role" : "General Manager", 
                "startdate" : ISODate("1970-01-01T00:00:00.000+0000"), 
                "enddate" : ISODate("1980-01-01T00:00:00.000+0000"), 
                "permissions" : "GM"
            }, 
            "1234" : {
                "role" : "Owner", 
                "startdate" : ISODate("1970-01-01T00:00:00.000+0000"), 
                "enddate" : null, 
                "permissions" : "ALL"
            }, 
            "4321" : {
                "role" : "Owner", 
                "startdate" : ISODate("1990-01-01T00:00:00.000+0000"), 
                "enddate" : null, 
                "permissions" : "ALL"
            }
        }
}

...但我需要商店列表采用这种形式(“商店”数组):

{ "name" : "John Smith",
  "store_affiliation" : {
        "stores" : [
            {
                "store_code" : "ABCD", 
                "role" : "General Manager", 
                "startdate" : ISODate("1970-01-01T00:00:00.000+0000"), 
                "enddate" : ISODate("1980-01-01T00:00:00.000+0000"), 
                "permissions" : "GM"
            }, 
            {
                "store_code" : "1234", 
                "role" : "Owner", 
                "startdate" : ISODate("1970-01-01T00:00:00.000+0000"), 
                "enddate" : null, 
                "permissions" : "ALL"
            }, 
            {
                "shop_id" : "4321", 
                "role" : "Owner", 
                "startdate" : ISODate("1990-01-01T00:00:00.000+0000"), 
                "enddate" : null, 
                "permissions" : "ALL"
            }
        ]
}

我研究过在aggregate 管道中使用$project$group$push,但我觉得使用aggregate 甚至可能是死路一条,因为我不是在查询结果;我正在尝试永久修改集合中的每个文档(数千个)。

【问题讨论】:

    标签: mongodb aggregation-framework


    【解决方案1】:

    您可以在3.4 版本中尝试以下聚合管道。

    以下聚合将 stores 嵌入文档更改为键值对数组,使用 $objectToArray 后跟 $map 以输出转换后的数组,其中包含新字段,同时保留所有现有字段。

    批量更新以编写新的商店结构。

    var bulk = db.getCollection(col).initializeUnorderedBulkOp();
    var count = 0;
    var batch = 1;
    
    db.getCollection(col).aggregate([
    {"$match":{"store_affiliation.stores":{"$ne":{"$type":4}}}},
    {"$addFields":{
      "stores":{
          "$map":{
            "input":{"$objectToArray": "$store_affiliation.stores"}, 
            "in":{
               "store_code":"$$this.k", 
               "role":"$$this.v.role", 
               "startdate":"$$this.v.startdate", 
               "enddate":"$$this.v.enddate", 
               "permissions":"$$this.v.permissions"
             }
          }
        }
    }}]).forEach(function(doc){ 
        var _id = doc._id; 
        var stores = doc.stores; 
        bulk.find({ "_id" : _id }).updateOne(
          { $set: {"store_affiliation.stores" : stores} }
       ); 
        count++;  
        if (count == batch) { 
            bulk.execute(); 
            bulk = db.getCollection(col).initializeUnorderedBulkOp(); 
            count = 0;
        } 
    });
    
    if (count > 0) { 
        bulk.execute(); 
    }
    

    【讨论】:

    • 这很好,虽然它总是返回一个错误:“$objectToArray 需要一个文档输入,找到:数组”。它成功地转换了我需要的每个文档,所以它可能正试图循环回已经转换的文档?如果将来有人偶然发现此问题,我将尝试将问题作为建议的编辑来纠正。
    • 不,您可能已经有一些数组文件。我添加了检查以确保它只查看非数组记录。您可以运行db.col.find({"store_affiliation.stores":{"$type":4}}) 来检查是否有任何数组。
    猜你喜欢
    • 1970-01-01
    • 2021-09-17
    • 1970-01-01
    • 2020-06-17
    • 2021-03-11
    • 2020-10-04
    • 2023-02-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多