0

I want to get a result of updating two json data, the second json updated existing data from first json and also it has new data as well, these are my structure:

var origin = {
  "allTest": [
    {
      "testName": "A",
      "platform": [{"name": "chrome", "area": ["1"]}]
    },
    {
      "testName": "B",
      "platform": [{"name": "Edge", "area": ["2"]}]
    }
  ]
};

var updated = {
  "allTest": [
    {
      "testName": "A",
      "platform": [{"name": "chrome", "area": ["1"]}]
    },
    {
      "testName": "B",
      "platform": [{"name": "Safari", "area": ["3"]}]
    },
    {
      "testName": "C",
      "platform": [{"name": "IE", "area": ["4"]}]
    }
  ]
}

var result = origin.allTest.concat(updated.allTest);
console.log(result);

result:

  [ { testName: 'A', platform: [ [Object] ] },
  { testName: 'B', platform: [ [Object] ] },
  { testName: 'A', platform: [ [Object] ] },
  { testName: 'B', platform: [ [Object] ] },
  { testName: 'C', platform: [ [Object] ] } ]

but this is not the current update, i would like to update origin data like this:

expected result:

{
  "allTest": [
    {
      "testName": "A",
      "platform": [{"name": "chrome", "area": ["1"]}]
    },
    {
      "testName": "B",
      "platform": [{"name": "Edge", "area": ["2"]},{"name": "Safari", "area": ["3"]}]
    },
    {
      "testName": "C",
      "platform": [{"name": "IE", "area": ["4"]}]
    }
  ]
}

can you please help me to solve it. i am new in codding, thanks

Alex
  • 315
  • 2
  • 5
  • 14
  • Have a look: https://stackoverflow.com/questions/18498801/how-to-merge-two-object-values-by-keys – PM 77-1 Jan 29 '19 at 22:56

4 Answers4

0

Use a JsonPatch. Depending on the technology you are using, you'll find different tools to implement this. A JsonPatch document is basically a Json that describes the changes in the original document.

0

You can use the spread operator like this:

var result = { ...origin, ...updated };
Per Digesen
  • 99
  • 1
  • 5
  • [`...` is not an operator!](https://stackoverflow.com/questions/37151966/what-is-spreadelement-in-ecmascript-documentation-is-it-the-same-as-spread-oper/37152508#37152508) – Felix Kling Jan 29 '19 at 23:06
0

You could use a function to iterate recursively through the target object and add it appropriately.

From what I understand of your structure, you need specific logic to deal with concatenating the platforms if the testname is equal. I wrote a quick function as an example here, but this one does not check for duplicates. Forgive me for the sloppy code, I am new to javascript as well.

var origin = {
  "allTest": [
    {
      "testName": "A",
      "platform": [{"name": "chrome", "area": ["1"]}]
    },
    {
      "testName": "B",
      "platform": [{"name": "Edge", "area": ["2"]}]
    }
  ]
};

var updated = {
  "allTest": [
    {
      "testName": "A",
      "platform": [{"name": "chrome", "area": ["1"]}]
    },
    {
      "testName": "B",
      "platform": [{"name": "Safari", "area": ["3"]}]
    },
    {
      "testName": "C",
      "platform": [{"name": "IE", "area": ["4"]}]
    }
  ]
}

function concatJson(source, target)
{
    var result = target;

     for (var i in source.allTest)
     {
         var found = false;
         for (var j in result.allTest)
         {
             //if the testname is the same we need to concat the platform
             if(!found && source.allTest[i].testName == result.allTest[j].testName)
             {
                result.allTest[i].platform = source.allTest[i].platform.concat(result.allTest[j].platform)
                found = true;
             }
        }
        if(!found)
        {
            //no match found so we'll add the tuple to the list
            result.allTest = result.allTest.concat(source.allTest[i]);
        }
    }
    return result;
}

var result = concatJson(updated, origin);
console.log(JSON.stringify(result, null, 4));
Glen654
  • 1,102
  • 3
  • 14
  • 18
0

Here is a solution that doesn't use libraries, but it's not dynamic so it's tailored to your use case only.

I got blocked, and wasn't able to make it more optimal so any feedback is welcome :)

const origin = {
  allTest: [
    {
      testName: 'A',
      platform: [{ name: 'chrome', area: ['1'] }],
    },
    {
      testName: 'B',
      platform: [{ name: 'Edge', area: ['2'] }],
    },
  ],
}

const updated = {
  allTest: [
    {
      testName: 'A',
      platform: [{ name: 'chrome', area: ['1'] }],
    },
    {
      testName: 'B',
      platform: [{ name: 'Safari', area: ['3'] }],
    },
    {
      testName: 'C',
      platform: [{ name: 'IE', area: ['4'] }],
    },
  ],
}

const findAndMergePlatforms = (array, item) =>
  array
    .filter(o => o.testName === item.testName)
    .map(o => ({ ...o, platform: [...o.platform, ...item.platform] }))

const removeExisting = (array, item) =>
  array.filter(o => o.testName !== item.testName)

const removeDuplicatePlatforms = platforms =>
  platforms.reduce(
    (acc, curr) =>
      acc.filter(({ name }) => name === curr.name).length > 0
        ? acc
        : [...acc, curr],
    []
  )

const mergedAllTests =
  // Merge "allTest" objects from both arrays
  [...origin.allTest, ...updated.allTest]

    // Merge the "platform" properties
    .reduce((acc, curr) => {
      const found = findAndMergePlatforms(acc, curr)
      acc = removeExisting(acc, curr)
      return found.length !== 0 ? [...acc, ...found] : [...acc, curr]
    }, [])

    // Remove platform duplicates
    .map(({ testName, platform }) => ({
      testName,
      platform: removeDuplicatePlatforms(platform),
    }))

const result = { allTest: mergedAllTests }

const util = require('util')
console.log(util.inspect(result, { showHidden: false, depth: null }))

Edit: Added comments, and fixed the result to include allTest object.

Samer
  • 973
  • 1
  • 6
  • 15