Search code examples
javascriptarraysdenormalization

How to denormalize array in JS


I have a data set of the following form

let data = [
  {
    "id": {
      "primary": "A1"
    },
    "msg": 1
  }, {
    "id": {
      "primary": "A1"
    },
    "msg": 2
  }, {
    "id": {
      "primary": "B2"
    },
    "msg": 3
  }
]

I would like to transform it to

newData = [
  {
    "id": {
      "primary": "A1"
    },
    "items": [
      { "msg": 1 },
      { "msg": 2 }
    ]
  },
  {
    "id": {
      "primary": "B2"
    },
    "items": [
      { "msg": 3 }
    ]
  }
]

I think the method is something like the following, but am not sure how to check against undefined values in this case.

let newData = [];
for (let i = 0; i < data.length; i++) {
  if (newData[i]['id']['primary'] === data[i]['id']) newData.push(data[i]['id'])
  else newData[i]['items'].push(data[i]['msg'])
}

How can I transform the original data set to merge entries with a matching primary id?


Solution

  • You could also solve this in a concise way via the Array.reduce and ES6 destructuring:

    let data = [ { "id": { "primary": "A1" }, "msg": 1 }, { "id": { "primary": "A1" }, "msg": 2 }, { "id": { "primary": "B2" }, "msg": 3 } ]
    
    let result = data.reduce((r, {id, msg}) => 
      ((r[id.primary] = r[id.primary] || { id, items: [] }).items.push({msg}), r), {})
    
    console.log(Object.values(result))

    In more readable format it is:

    let data = [ { "id": { "primary": "A1" }, "msg": 1 }, { "id": { "primary": "A1" }, "msg": 2 }, { "id": { "primary": "B2" }, "msg": 3 } ]
    
    let result = data.reduce((r, {id, msg}) => {
      r[id.primary] = (r[id.primary] || { id, items: [] })
      r[id.primary].items.push({msg})
      return r
    }, {})
    
    console.log(Object.values(result))

    The idea is to group by the id.primary and then once the grouping is done simply get the values via Object.values

    Notice that this is one pass solution where you do not have to per each iteration do an Array.find against the current accumulator.