简体   繁体   English

合并源 JSON 字符串以在 javascript 中使用相似的键但结构不同

[英]Merge source JSON string to target with similar keys but different structure in javascript

I have two JSON strings as shown below:我有两个 JSON 字符串,如下所示:

source =来源 =

[
{"name":"test1","values":["User Support"],"enabled":false},
{"name":"test2","values":["M"],"enabled":true},
{"name":"test3","values":["CA"],"enabled":false}
]

target =目标 =

[
{"name":"test1","values":[
 {"value":"User Support","selected":false},
 {"value":"Engineering","selected":false},
 {"value":"Implementation","selected":false}],"enabled":false
},
{
 "name":"test2","values":
 [
  {"value":"M","selected":false},
  {"value":"F","selected":false}
 ],"notEnabled":false
},
{
 "name":"test3","values":
 [
  {"value":"CA","selected":false},
  {"value":"EN","selected":false}
 ],"enabled":false
}
]

I want to merge both these JSON strings into target and the resultant should look like:我想将这两个 JSON 字符串合并到目标中,结果应如下所示:

target =目标 =

[
{"name":"test1","values":[
 {"value":"User Support","selected":true},
 {"value":"Engineering","selected":false},
 {"value":"Implementation","selected":false}],"enabled":false
},
{
 "name":"test2","values":
 [
  {"value":"M","selected":true},
  {"value":"F","selected":false}
 ],"enabled":true
},
{
 "name":"test3","values":
 [
  {"value":"CA","selected":true},
  {"value":"EN","selected":false}
 ],"enabled":false
}
]

So, what I am trying to do is search in target string for name as test1, test2.... and then set the selected field as true if the value is found in source JSON string.所以,我想要做的是在目标字符串中搜索名称为 test1、test2.... 然后如果在源 JSON 字符串中找到该值,则将所选字段设置为 true。 Same is the case for enabled field.启用字段的情况也是如此。

First thing that comes to my mind is to use nested for each loops and check for the keys.我想到的第一件事是对每个循环使用嵌套并检查键。 Is there any other better way to do this in Javascript?在 Javascript 中还有其他更好的方法可以做到这一点吗?

Note that there could be other keys present inside target string, but we don't bother about them unless they are present in source string.请注意,目标字符串中可能存在其他键,但除非它们出现在源字符串中,否则我们不会理会它们。

If you don't mind lodash:如果你不介意 lodash:

const _ = require('lodash');

const sourceJSON = '[{"name":"test1","values":["User Support"],"enabled":false},{"name":"test2","values":["M"],"enabled":true},{"name":"test3","values":["CA"],"enabled":false}]';
const targetJSON = '[{"name":"test1","values":[{"value":"User Support","selected":false}, {"value":"Engineering","selected":false},{"value":"Implementation","selected":false}],"enabled":false},{"name":"test2","values":[{"value":"M","selected":false},  {"value":"F","selected":false} ],"notEnabled":false},{ "name":"test3","values": [{"value":"CA","selected":false},{"value":"EN","selected":false}],"enabled":false}]';

const source = JSON.parse(sourceJSON);
const target = JSON.parse(targetJSON);

const sourceNormalized = source.map((obj) => (
  { ...obj, values: [{value: obj.values[0], selected: true}] }
));

const merged = _.defaultsDeep(sourceNormalized, target);
console.dir(merged, {depth: null});
// [ { name: 'test1',
//     values: [
//       { value: 'User Support', selected: true },
//       { value: 'Engineering', selected: false },
//       { value: 'Implementation', selected: false }
//     ],
//     enabled: false
//   },
//   { name: 'test2',
//     values: [ 
//       { value: 'M', selected: true }, 
//       { value: 'F', selected: false } 
//     ],
//     enabled: true,
//     notEnabled: false
//   },
//   { name: 'test3',
//     values: [
//       { value: 'CA', selected: true },
//       { value: 'EN', selected: false }
//     ],
//     enabled: false} ] 

result = JSON.stringify(merged);

The previous answer using lodash is a very good approach.上一个使用 lodash 的答案是一个非常好的方法。 In case you are in a situation such as myself (stuck working on a code-base where packages, including lodash, are difficult to get approved-for-use), here is an approach using Vanilla-javascript (+ JSON.stringify):如果您遇到像我这样的情况(坚持在代码库上工作,其中包括 lodash 在内的包难以获得批准使用),这里有一种使用 Vanilla-javascript (+ JSON.stringify) 的方法:

 const delta = [{ "name": "test1", "values": ["User Support"], "enabled": false }, { "name": "test2", "values": ["M"], "enabled": true }, { "name": "test3", "values": ["CA"], "enabled": false } ]; const orig = [{ "name": "test1", "values": [{ "value": "User Support", "selected": false }, { "value": "Engineering", "selected": false }, { "value": "Implementation", "selected": false } ], "enabled": false }, { "name": "test2", "values": [{ "value": "M", "selected": false }, { "value": "F", "selected": false } ], "notEnabled": false }, { "name": "test3", "values": [{ "value": "CA", "selected": false }, { "value": "EN", "selected": false } ], "enabled": false } ]; const getTargetJSON = (delta, orig, debug = true) => { // method signature const deltaMapper = delta.reduce((f, i) => ({ ...f, [i.name]: { values: [...i.values], enabled: i.enabled } }), {}); const target = orig.map(itm => ({ ...itm, values: itm.values.map(it2 => ({ ...it2, selected: deltaMapper[itm.name].values.includes(it2.value) || false })), enabled: deltaMapper[itm.name].enabled || false })); debug && console.log('Merged Target:\\n', target); return JSON.stringify(target); }; getTargetJSON(delta, orig); // method call

Approach / Explanation :方法/解释

We breakdown the problem into smaller ones.我们将问题分解为更小的问题。

  • First, generate a map using the source (named 'delta' in code-snippet)首先,使用源生成地图(在代码片段中命名为“delta”)
  • Next, iterate through the target (named 'orig') and utilize the map (created above) to determine whether value is 'selected' and item is 'enabled'.接下来,遍历目标(名为“orig”)并利用映射(上面创建的)来确定值是否为“选择”和项目是否为“启用”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM