Nick The Dev
Nick The Dev

Reputation: 3

Merge Objects With Same JSON Key

I'm having some troubles merging an array of JSON objects together by key. Would anyone have a good solution to this using just Javascript?

{
    "code": "12345",
    "error": "12345 error 1"
},
{
    "code": "12345",
    "error": "12345 error 2"
},
{
    "code": "67890",
    "error": "67890 error 1"
},
{
    "code": "67890",
    "error": "67890 error 2"
},
{
    "code": "67890",
    "error": "67890 error 3"
},
{
    "code": "67890",
    "error": "67890 error 4"
},
{
    "code": "67890",
    "error": "67890 error 5"
},
{
    "code": "12092",
    "error": "12092 error 1"
},
{
    "code": "12092",
    "error": "12092 error 2"
}

Should be transformed to

{
    "code": "12345",
    "error": "12345 error 1, 12345 error 2"
},
{
    "code": "67890",
    "error": "67890 error 1, 67890 error 2, 67890 error 3, 67890 error 4, 67890 error 5"
},
{
    "code": "12092",
    "error": "12092 error 1, 12092 error 2"
}

Any help would be greatly appreciated. I've racked my brain over this for a long time and just cant seem to get it down.

Upvotes: 0

Views: 70

Answers (3)

brk
brk

Reputation: 50346

Use array reduce to create the new merged array of objects. Inside the callback function check if the accumulator array have an object which already have the code. For this use findIndex. If the code matches then update the error. Else push the current object in the accumulator

const data = [{"code":"12345","error":"12345 error 1"},{"code":"12345","error":"12345 error 2"},{"code":"67890","error":"67890 error 1"},{"code":"67890","error":"67890 error 2"},{"code":"67890","error":"67890 error 3"},{"code":"67890","error":"67890 error 4"},{"code":"67890","error":"67890 error 5"},{"code":"12092","error":"12092 error 1"},{"code":"12092","error":"12092 error 2"}];

let mergedData = data.reduce(function(acc, curr) {
  let findIndex = acc.findIndex(function(item) {
    return item.code === curr.code;
  })
  if (findIndex === -1) {
    acc.push(curr)
  } else {
    acc[findIndex].error += ', ' + curr.error
  }
  return acc;
}, []);

console.log(mergedData)

Upvotes: 4

Charlie Schliesser
Charlie Schliesser

Reputation: 8246

The existing answer using Reduce and checking for the existing object key is perfect.

Here's another method of doing this using Map and other ES6 syntax (for...of) that I think is easy to read and just another interesting approach:

const data = [{"code":"12345","error":"12345 error 1"},{"code":"12345","error":"12345 error 2"},{"code":"67890","error":"67890 error 1"},{"code":"67890","error":"67890 error 2"},{"code":"67890","error":"67890 error 3"},{"code":"67890","error":"67890 error 4"},{"code":"67890","error":"67890 error 5"},{"code":"12092","error":"12092 error 1"},{"code":"12092","error":"12092 error 2"}];

// Define a new empty Map.
const map = new Map();

// Loop through all data objects.
for (const dataEntry of data) {

  // Check if we've already added this to our map; if not, add blank entry.
  if (!map.has(dataEntry.code)) {
      map.set(dataEntry.code, {code: dataEntry.code,error:[]});
  }

  // Append to the error property.
  const mapEntry = map.get(dataEntry.code);
  mapEntry.error.push(dataEntry.error);

}

// Flatten the error entries to be a single String instead of an Array.
for (const entry of map.values()) {
  entry.error = entry.error.join(', ');
}

const output = Array.from(map.values());

console.log(output);

Upvotes: 1

kockburn
kockburn

Reputation: 17636

Using Array#from, Array#reduce, Array#map and Map you could do somethign like this.

Idea is to first regroup everything with the Array#reduce and Map, and then to transform the data to the output you seek using Array#map.

const data = [{"code":"12345","error":"12345 error 1"},{"code":"12345","error":"12345 error 2"},{"code":"67890","error":"67890 error 1"},{"code":"67890","error":"67890 error 2"},{"code":"67890","error":"67890 error 3"},{"code":"67890","error":"67890 error 4"},{"code":"67890","error":"67890 error 5"},{"code":"12092","error":"12092 error 1"},{"code":"12092","error":"12092 error 2"}];

const res = Array.from(
  data.reduce((a,{code, error})=>{
    return a.set(code, [error].concat(a.get(code)||[]))
  }, new Map())
).map(([code, error])=>({code, error: error.join(",")}));

console.log(res);

Upvotes: 1

Related Questions