【问题标题】:How to Restructure Document Fields Into An Array如何将文档字段重组为数组
【发布时间】:2017-12-02 10:01:53
【问题描述】:

我有一些如下所示的数据:

{
  "name" : "someValue",
  "date" : "someValue",
  "age" : "someValue",
  "price" : "someValue",
  "sales_comp1" : "someValue",
  "sales_comp1_dos" : "someValue",
  "sales_comp1_units" : "someValue",
  "sales_comp1_NOI_unit" : "someValue",
  "sales_comp1_sales_pr_unit" : "someValue",
  "sales_comp1_adj_SPrice" : "someValue",
  "sales_comp1_cap_rate" : "someValue",
  "sales_comp2" : "someValue",
  "sales_comp2_dos" : "someValue",
  "sales_comp2_units" : "someValue",
  "sales_comp2_NOI_unit" : "someValue",
  "sales_comp2_sales_pr_unit" : "someValue",
  "sales_comp2_adj_SPrice" : "someValue",
  "sales_comp2_cap_rate" : "someValue",
  "sales_comp3" : "someValue",
  "sales_comp3_dos" : "someValue",
  "sales_comp3_units" : "someValue",
  "sales_comp3_NOI_unit" : "someValue",
  "sales_comp3_sales_pr_unit" : "someValue",
  "sales_comp3_adj_SPrice" : "someValue",
  "sales_comp3_cap_rate" : "someValue"
}

我想将 sales_compX 值合并到一个名为 salesComps 的数组中:

{
  "name" : "someValue",
  "date" : "someValue",
  "age" : "someValue",
  "price" : "someValue",
  "salesComps" : [
    {
      "sales_comp1" : "someValue",
      "sales_comp1_dos" : "someValue",
      "sales_comp1_units" : "someValue",
      "sales_comp1_NOI_unit" : "someValue",
      "sales_comp1_sales_pr_unit" : "someValue",
      "sales_comp1_adj_SPrice" : "someValue",
      "sales_comp1_cap_rate" : "someValue",
    },
    {
      "sales_comp2" : "someValue",
      "sales_comp2_dos" : "someValue",
      "sales_comp2_units" : "someValue",
      "sales_comp2_NOI_unit" : "someValue",
      "sales_comp2_sales_pr_unit" : "someValue",
      "sales_comp2_adj_SPrice" : "someValue",
      "sales_comp2_cap_rate" : "someValue",
    },
    {
      "sales_comp3" : "someValue",
      "sales_comp3_dos" : "someValue",
      "sales_comp3_units" : "someValue",
      "sales_comp3_NOI_unit" : "someValue",
      "sales_comp3_sales_pr_unit" : "someValue",
      "sales_comp3_adj_SPrice" : "someValue",
      "sales_comp3_cap_rate" : "someValue"
    }
  ]
}

最简单的方法是什么?我将不胜感激 Mongoose 或 Mongodb 代码示例中的任何响应!

【问题讨论】:

    标签: javascript node.js mongodb mongoose nosql


    【解决方案1】:

    首先,使用Object.keys() 遍历数据并等待“sales_comp”数据出现。当它确实将键值对插入到持有对象中并从主数据中删除该条目时。一旦完成,将持有对象添加回数据中。像这样的...

    数据...

    var data = {
      "name" : "someValue",
      "date" : "someValue",
      "age" : "someValue",
      "price" : "someValue",
      "sales_comp1" : "someValue",
      "sales_comp1_dos" : "someValue",
      "sales_comp1_units" : "someValue",
      "sales_comp1_NOI_unit" : "someValue",
      "sales_comp1_sales_pr_unit" : "someValue",
      "sales_comp1_adj_SPrice" : "someValue",
      "sales_comp1_cap_rate" : "someValue",
      "sales_comp2" : "someValue",
      "sales_comp2_dos" : "someValue",
      "sales_comp2_units" : "someValue",
      "sales_comp2_NOI_unit" : "someValue",
      "sales_comp2_sales_pr_unit" : "someValue",
      "sales_comp2_adj_SPrice" : "someValue",
      "sales_comp2_cap_rate" : "someValue",
      "sales_comp3" : "someValue",
      "sales_comp3_dos" : "someValue",
      "sales_comp3_units" : "someValue",
      "sales_comp3_NOI_unit" : "someValue",
      "sales_comp3_sales_pr_unit" : "someValue",
      "sales_comp3_adj_SPrice" : "someValue",
      "sales_comp3_cap_rate" : "someValue"
    };
    

    代码...

    // holding Object
    var tmpStorage = {};
    
    // Loop through the data
    Object.keys(data).forEach(function(d) {
         // look for 'sales_comp' keys
         if (/sales_comp/.test(d)) {
             // find which 'sales_comp' each 'd'
             // belongs to with simple regex (allowing
             // for more than single digits here)
             var id = d.match(/sales_comp([\d]+)/)[1];
             // create a tmp property for tmpStorage object
             // if it doesn't exist (which it wont on the
             // the first pass)
             tmpStorage['tmp'+id] = tmpStorage['tmp'+id] || {};
             // add the current key-value pair to the
             // tmpStorage Object
             tmpStorage['tmp'+id][d] = data[d];
             // remove the current key-value pair from the
             // data object
             delete data[d]
         }
    });
    

    “数据”对象现在看起来像这样......

    console.log('data:',data);
    /* =>
    data: {
      name: 'someValue',
      date: 'someValue',
      age: 'someValue',
      price: 'someValue'
    }
    */
    

    而 tmpStorage 对象看起来像这样......

    console.log('tmpStorage:',tmpStorage);
    /* =>
    tmpStorage: {
      tmp1: {
         sales_comp1: 'someValue',
         sales_comp1_dos: 'someValue',
         sales_comp1_units: 'someValue',
         sales_comp1_NOI_unit: 'someValue',
         sales_comp1_sales_pr_unit: 'someValue',
         sales_comp1_adj_SPrice: 'someValue',
         sales_comp1_cap_rate: 'someValue'
      },
      tmp2: {
         sales_comp2: 'someValue',
         sales_comp2_dos: 'someValue',
         sales_comp2_units: 'someValue',
         sales_comp2_NOI_unit: 'someValue',
         sales_comp2_sales_pr_unit: 'someValue',
         sales_comp2_adj_SPrice: 'someValue',
         sales_comp2_cap_rate: 'someValue'
      },
      tmp3: {
         sales_comp3: 'someValue',
         sales_comp3_dos: 'someValue',
         sales_comp3_units: 'someValue',
         sales_comp3_NOI_unit: 'someValue',
         sales_comp3_sales_pr_unit: 'someValue',
         sales_comp3_adj_SPrice: 'someValue',
         sales_comp3_cap_rate: 'someValue'
      }
    }
    */
    

    现在只需将 'tmpStorage' 的内容推送到新的 'data.salesComps' 数组中

    data.salesComps = Object.keys(tmpStorage).map(function(t) {
        return tmpStorage[t];
    });
    

    现在“数据”看起来像这样......

    console.log('data:',data);
    /* =>
    data: { 
      name: 'someValue',
      date: 'someValue',
      age: 'someValue',
      price: 'someValue',
      salesComps: [
         { sales_comp1: 'someValue',
           sales_comp1_dos: 'someValue',
           sales_comp1_units: 'someValue',
           sales_comp1_NOI_unit: 'someValue',
           sales_comp1_sales_pr_unit: 'someValue',
           sales_comp1_adj_SPrice: 'someValue',
           sales_comp1_cap_rate: 'someValue'
         },
         { sales_comp2: 'someValue',
           sales_comp2_dos: 'someValue',
           sales_comp2_units: 'someValue',
           sales_comp2_NOI_unit: 'someValue',
           sales_comp2_sales_pr_unit: 'someValue',
           sales_comp2_adj_SPrice: 'someValue',
           sales_comp2_cap_rate: 'someValue' 
        },
        {  sales_comp3: 'someValue',
           sales_comp3_dos: 'someValue',
           sales_comp3_units: 'someValue',
           sales_comp3_NOI_unit: 'someValue',
           sales_comp3_sales_pr_unit: 'someValue',
           sales_comp3_adj_SPrice: 'someValue',
           sales_comp3_cap_rate: 'someValue' 
        }
      ]
    }
    */
    

    它可能看起来很复杂,但是一旦你取出所有的 cmets,你会发现它是一个相对简单的两阶段过程 - 删除你需要的数据,然后以你想要的格式添加回来。

    希望有所帮助:)

    【讨论】:

      【解决方案2】:

      一次性操作可能最好在 mongo shell 中完成,它有 JavaScript 环境来处理这个,而无需担心回调和承诺的考虑。

      所以这里最好的做法是循环收集结果并在将字段转换为数组后通过.bulkWrite()方法重新写入集合:

      var name = "collection";  
      var ops = [];
      
      db.getCollection(name).find().forEach(doc => {
      
          var obj = Object.keys(doc).filter(k => /^sales_comp/.test(k))
           .map( k => ({ [k.match(/\d+/)[0]]: { [k.replace(/\d+/,"")]: doc[k] }}))
           .reduce((acc,curr) => {
             let a = Object.keys(curr)[0];
             if ( !acc.hasOwnProperty(a) )
               acc[a] = { };
             acc[a][Object.keys(curr[a])[0]] = curr[a][Object.keys(curr[a])[0]];
             return acc;
           },{});
      
          // Un-comment and swap if you don't want to retain the index number
          //var comps = Object.keys(obj).map( k => obj[k] )
          var comps = Object.keys(obj).map( k => Object.assign({ "index": parseInt(k) },obj[k]) );
      
          var unset = Object.keys(doc).filter(k => /^sales_comp/.test(k))
            .reduce((acc,curr) => Object.assign(acc,({ [curr]: 1 })),{});
      
          ops.push({
            "updateOne": {
              "filter": { "_id": doc._id },
              "update": {
                "$unset": unset,
                "$set": { "salesComps": comps }   
              }
            }        
          });
      
          if ( ops.length >= 500 ) {
            db.getCollection(name).bulkWrite(ops);
            ops = [];
          }
      });
      
      if ( ops.length > 0 ) {
        db.getCollection(name).bulkWrite(ops);
        ops = [];   
      }
      

      这会像这样重写每个文档:

      {
          "_id" : ObjectId("5954461a38470d375d40aca1"),
          "name" : "someValue",
          "date" : "someValue",
          "age" : "someValue",
          "price" : "someValue",
          "salesComps" : [ 
              {
                  "index" : 1,
                  "sales_comp" : "someValue",
                  "sales_comp_dos" : "someValue",
                  "sales_comp_units" : "someValue",
                  "sales_comp_NOI_unit" : "someValue",
                  "sales_comp_sales_pr_unit" : "someValue",
                  "sales_comp_adj_SPrice" : "someValue",
                  "sales_comp_cap_rate" : "someValue"
              }, 
              {
                  "index" : 2,
                  "sales_comp" : "someValue",
                  "sales_comp_dos" : "someValue",
                  "sales_comp_units" : "someValue",
                  "sales_comp_NOI_unit" : "someValue",
                  "sales_comp_sales_pr_unit" : "someValue",
                  "sales_comp_adj_SPrice" : "someValue",
                  "sales_comp_cap_rate" : "someValue"
              }, 
              {
                  "index" : 3,
                  "sales_comp" : "someValue",
                  "sales_comp_dos" : "someValue",
                  "sales_comp_units" : "someValue",
                  "sales_comp_NOI_unit" : "someValue",
                  "sales_comp_sales_pr_unit" : "someValue",
                  "sales_comp_adj_SPrice" : "someValue",
                  "sales_comp_cap_rate" : "someValue"
              }
          ]
      }
      

      这基本上是检查文档中以"sales_comp" 开头的“键”的名称,并在根据字符串的数字部分累积键并将其从名称中剥离出来后,将数据转换为数组对于每个不同的数值。

      当实际处理对目标集合的“更新”时,我们在以"sales_comp 开头的字段上使用$unset 运算符将这些从文档中删除。然后我们使用$set 运算符和转换后的数组来创建新属性。

      这里有一些使用 .map().reduce().filter() 的常用习惯用法,在 JavaScript 中使用数据结构时应该熟悉这些习惯用法。

      【讨论】:

        猜你喜欢
        • 2020-05-09
        • 2012-08-07
        • 1970-01-01
        • 2015-10-19
        • 1970-01-01
        • 1970-01-01
        • 2022-11-02
        • 1970-01-01
        • 2021-07-20
        相关资源
        最近更新 更多