对象复杂的转换

时间:2017-07-02 06:41:07

标签: javascript json

我试图找到一个好的实用程序( Lodash 或其他一些)来帮助转换相当深度嵌套的对象,如下所示:

源数据:

  [{
  "category": "blogs",
  "results": {
      "__type": "SearchProvider.SearchResultContainer",
      "SearchResults": [{
          "SearchId": null,
          "MetaData": [{
              "Name": "id",
              "Value": "618",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PostID",
              "Value": "618",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PublishDate",
              "Value": "10/08/2012 6:28:00 AM",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "_version_",
              "Value": 1571711408793452500,
              "Other": "",
              "Count": 0,
              "Checked": true
          }]
      }, {
          "SearchId": null,
          "MetaData": [{
              "Name": "id",
              "Value": "605",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PostID",
              "Value": "605",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PublishDate",
              "Value": "03/01/2011 8:16:00 PM",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "_version_",
              "Value": 1571711408284893200,
              "Other": "",
              "Count": 0,
              "Checked": true
          }]
      }]
  }
}]

并生成此结果,以便从每个id对象中的PublishDate数组中获取属性名称MetaDataSearchResults及其值:

预期数据:

[
    {
        "id": "618",
        "PublishDate": "10/08/2012 6:28:00 AM"
    },
    {
        "id": "605",
        "PublishDate": "03/01/2011 8:16:00 PM"
    }
]

我已尝试使用json-query并发现语法易于理解,尤其是使用在线测试工具(https://maxleiko.github.io/json-query-tester/),但无法产生此结果。

此问题标记为"暂停"说它没有达到指导方针,因为它要求提供建议"而不是一个明确的解决方案虽然我理解寻求建议和获得主观回答列表的任意性,但我在这里要求推荐的意义并不是这样。我要求经验丰富的JS开发人员提供反馈和不同的模式(内置的ES6对象或其他实用程序库,例如Lodash)他们将如何得到这个结果(客观地)。所以从这个意义上说,有一个客观的问题和答案被要求。但我明白,因为有不同的方法来获得这个结果,所以不容易识别单个答案。我相信这更多地说明了SO格式的限制(在这种情况下),其中一个问题变成了#34;关于主题"。如果还有另一个地方可以发布这种最适合各种良好反应的最佳实践方法(比如问题所得到的反应),那么我很乐意在那里发帖。无论如何,提供给这个问题的两个答案都帮助我理解了如何通过两种不同的方法解决这个问题。 ES6的答案帮助我理解了如何利用内置的ES6功能(破坏和扩展运算符)来获得结果。 Lodash的答案帮助我理解如何用它来完成。感谢那些已经提供答案的人 - 我希望我可以选择你的答案进行表彰(我明白为什么这个问题被标记为不符合SO指导原则)。

因为我确实声明我想使用"实用程序"像Lodash一样,我会选择Lodash的答案(即使ES6答案帮助我更好地使用其内置功能)。

2 个答案:

答案 0 :(得分:2)

Javascript具有解析此结构所需的所有工具,并且使用ES6箭头函数,并且解构使其更容易:



const data = [{"category":"blogs","results":{"__type":"SearchProvider.SearchResultContainer","SearchResults":[{"SearchId":null,"MetaData":[{"Name":"id","Value":"618","Other":"","Count":0,"Checked":true},{"Name":"PostID","Value":"618","Other":"","Count":0,"Checked":true},{"Name":"PublishDate","Value":"10/08/2012 6:28:00 AM","Other":"","Count":0,"Checked":true},{"Name":"_version_","Value":1571711408793452500,"Other":"","Count":0,"Checked":true}]},{"SearchId":null,"MetaData":[{"Name":"id","Value":"605","Other":"","Count":0,"Checked":true},{"Name":"PostID","Value":"605","Other":"","Count":0,"Checked":true},{"Name":"PublishDate","Value":"03/01/2011 8:16:00 PM","Other":"","Count":0,"Checked":true},{"Name":"_version_","Value":1571711408284893200,"Other":"","Count":0,"Checked":true}]}]}}];

const getValueFromMeta = (meta, name) => (meta.find(({ Name }) => Name === name) || {}).Value; // get a value from  metadata according to name

/** if the metadata structure is consistent you can use this instead
const propToIndex = { id: 0, PublishDate: 2 };
const getValueFromMeta = (meta, name) => (meta[propToIndex[name]] || {}).Value;
 **/

const result = [].concat( // flatten the arrays
  ...data.map(({ results }) => // map the data
    results.SearchResults.map(({ MetaData }) => ({ // map the search results, and create object
      id: getValueFromMeta(MetaData, 'id'), // get the value for id
      PublishDate: getValueFromMeta(MetaData, 'PublishDate') // get the value for publish date
  })))
);

console.log(result);




答案 1 :(得分:1)

使用lodash这可以很容易地完成:

var data = [{
  "category": "blogs",
  "results": {
      "__type": "SearchProvider.SearchResultContainer",
      "SearchResults": [{
          "SearchId": null,
          "MetaData": [{
              "Name": "id",
              "Value": "618",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PostID",
              "Value": "618",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PublishDate",
              "Value": "10/08/2012 6:28:00 AM",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "_version_",
              "Value": 1571711408793452500,
              "Other": "",
              "Count": 0,
              "Checked": true
          }]
      }, {
          "SearchId": null,
          "MetaData": [{
              "Name": "id",
              "Value": "605",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PostID",
              "Value": "605",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PublishDate",
              "Value": "03/01/2011 8:16:00 PM",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "_version_",
              "Value": 1571711408284893200,
              "Other": "",
              "Count": 0,
              "Checked": true
          }]
      }]
  }
}];

// transformation:
var newData = data[0].results.SearchResults.map(d => {
  return {
    id          : _.find(d.MetaData, {"Name":"id"}).Value,
    PublishDate : _.find(d.MetaData, {"Name":"PublishDate"}).Value
  }
})
    
    
console.log( newData )
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

使用ES2015 find方法:

var data = [{
  "category": "blogs",
  "results": {
      "__type": "SearchProvider.SearchResultContainer",
      "SearchResults": [{
          "SearchId": null,
          "MetaData": [{
              "Name": "id",
              "Value": "618",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PostID",
              "Value": "618",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PublishDate",
              "Value": "10/08/2012 6:28:00 AM",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "_version_",
              "Value": 1571711408793452500,
              "Other": "",
              "Count": 0,
              "Checked": true
          }]
      }, {
          "SearchId": null,
          "MetaData": [{
              "Name": "id",
              "Value": "605",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PostID",
              "Value": "605",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "PublishDate",
              "Value": "03/01/2011 8:16:00 PM",
              "Other": "",
              "Count": 0,
              "Checked": true
          }, {
              "Name": "_version_",
              "Value": 1571711408284893200,
              "Other": "",
              "Count": 0,
              "Checked": true
          }]
      }]
  }
}];


var newData = data[0].results.SearchResults.map(d => {
  return {
    id          : d.MetaData.find(item => item.Name == 'id').Value,
    PublishDate : d.MetaData.find(item => item.Name == 'PublishDate').Value
  }
}) 

console.log(newData)

防止可能丢失的密钥

例如,如果其中一个find方法与任何内容不匹配,则会返回undefinedundefined没有.value密钥它不是一个对象:

修正:

var newData = data[0].results.SearchResults.map(d => {
  return {
    id : (d.MetaData.find(item => item.Name == 'XXX')||{}).Value, // no match for "find" (undefined)
    PublishDate : (d.MetaData.find(item => item.Name == 'PublishDate')||{}).Value
  }
}) 

由于:

var a = [{foo:1}];

console.log( a.find(v => v).foo )        // = 1
console.log( (a.find(v => !v)||{}).foo ) // = undefined
console.log( a.find(v => !v).foo )       // ERROR