pinkdevelops
pinkdevelops

Reputation: 738

Merging JS objects with same key, values to an array

I am trying to merge JS objects together that have the same key. In this case the key I plan to use is the "time" field, and then for each time I want to include every "app" as a key, and "sum" as its value. The other fields I do not plan to include.

I've tried a few routes but still having trouble, code below:

var data = [
    {
        "eventdate": 1561334400000,
        "app": "cloudmark-desktop",
        "sum": 2970,
        "events": "2.9KiB",
        "time": "00:06"
    },
    {
        "eventdate": 1561334400000,
        "app": "dns",
        "sum": 519169,
        "events": "507.0KiB",
        "time": "00:06"
    },
    {
        "eventdate": 1561334400000,
        "app": "cloudmark-desktop",
        "sum": 999,
        "events": "507.0KiB",
        "time": "01:06"
    },
    {
        "eventdate": 1561334400000,
        "app": "dns",
        "sum": 999,
        "events": "507.0KiB",
        "time": "01:06"
    }
];

const result = data.reduce(function (r, e) {
    return Object.keys(e).forEach(function (k) {
        if (!r[k]) r[k] = [].concat(e[k])
        else r[k] = r[k].concat(e[k])
    }), r
}, {})

console.log(result)

This is how I want the data to output:


[
    {
        "time": "00:06",
        "cloudmark-desktop": 2970,
        "dns": 519169
    },
    {
        "time": "01:06",
        "cloudmark-desktop": 999,
        "dns": 999
    }
]

Any help appreciated! Thanks

Upvotes: 0

Views: 1172

Answers (6)

RQman
RQman

Reputation: 469

One of the possible solutions:

const data = [
    {
        "eventdate": 1561334400000,
        "app": "cloudmark-desktop",
        "sum": 2970,
        "events": "2.9KiB",
        "time": "00:06"
    },
    {
        "eventdate": 1561334400000,
        "app": "dns",
        "sum": 519169,
        "events": "507.0KiB",
        "time": "00:06"
    },
    {
        "eventdate": 1561334400000,
        "app": "cloudmark-desktop",
        "sum": 999,
        "events": "507.0KiB",
        "time": "01:06"
    },
    {
        "eventdate": 1561334400000,
        "app": "dns",
        "sum": 999,
        "events": "507.0KiB",
        "time": "01:06"
    }
];

const groupedDataByTime = data.reduce((accumulator, currentValue) => {
	if (!accumulator.hasOwnProperty(currentValue.time)) {
		accumulator[currentValue.time] = {};
	}
	
	const mapByTime = accumulator[currentValue.time];
	if (!mapByTime.hasOwnProperty(currentValue.app)) {
		mapByTime[currentValue.app] = 0;
	}
	mapByTime[currentValue.app] += parseInt(currentValue.sum, 10);
	
	return accumulator;
}, {});

const result = Object.keys(groupedDataByTime).map(time => {
	return Object.assign({ time }, groupedDataByTime[time]);
});

console.log(result);

Upvotes: 1

Vasi G.
Vasi G.

Reputation: 171

Here is another solution in pure JavaScript which is also more easy to read and understand:

var timesArray = [];
var uniqueTimesArray = [];
var result = [];
var items = [
    {
        "eventdate": 1561334400000,
        "app": "cloudmark-desktop",
        "sum": 2970,
        "events": "2.9KiB",
        "time": "00:06"
    },
    {
        "eventdate": 1561334400000,
        "app": "dns",
        "sum": 519169,
        "events": "507.0KiB",
        "time": "00:06"
    },
    {
        "eventdate": 1561334400000,
        "app": "cloudmark-desktop",
        "sum": 999,
        "events": "507.0KiB",
        "time": "01:06"
    },
    {
        "eventdate": 1561334400000,
        "app": "dns",
        "sum": 999,
        "events": "507.0KiB",
        "time": "01:06"
    }
];

function onlyUnique(value, index, self) { 
    return self.indexOf(value) === index;
}

items.forEach(function(element) {
  timesArray.push(element.time);
});

uniqueTimesArray = timesArray.filter( onlyUnique );

uniqueTimesArray.forEach(function(timeElement) {
  var resultItem = {};
  var key = "time";
  resultItem[key] = timeElement;
  items.forEach(function(item) {      
      if(item.time == timeElement){
          resultItem[item.app] = item.sum;
      }
  });
  result.push(resultItem);
});

console.log(result);

Upvotes: 0

Shridhar Sharma
Shridhar Sharma

Reputation: 2387

You were using {} in reduce method instead of []. Try this snippet for the shortest method to achieve this.

var data = [
    {
        "eventdate": 1561334400000,
        "app": "cloudmark-desktop",
        "sum": 2970,
        "events": "2.9KiB",
        "time": "00:06"
    },
    {
        "eventdate": 1561334400000,
        "app": "dns",
        "sum": 519169,
        "events": "507.0KiB",
        "time": "00:06"
    },
    {
        "eventdate": 1561334400000,
        "app": "cloudmark-desktop",
        "sum": 999,
        "events": "507.0KiB",
        "time": "01:06"
    },
    {
        "eventdate": 1561334400000,
        "app": "dns",
        "sum": 999,
        "events": "507.0KiB",
        "time": "01:06"
    }
];

const result = data.reduce(function (r, e) {
    let val = r.find(({time}) => time === e.time)
    if (!val) {
        val = {}
        r.push(val)
    }
    val.time = e.time;
    val[e.app] = e.sum;
    return r;
}, []);

console.log(result)

Upvotes: 1

Mehran Hatami
Mehran Hatami

Reputation: 12961

If you prefer doing it without the help of libraries like lodash you can do it like this:

var data = [
{
    "eventdate": 1561334400000,
    "app": "cloudmark-desktop",
    "sum": 2970,
    "events": "2.9KiB",
    "time": "00:06"
},
{
    "eventdate": 1561334400000,
    "app": "dns",
    "sum": 519169,
    "events": "507.0KiB",
    "time": "00:06"
},
{
    "eventdate": 1561334400000,
    "app": "cloudmark-desktop",
    "sum": 999,
    "events": "507.0KiB",
    "time": "01:06"
},
{
    "eventdate": 1561334400000,
    "app": "dns",
    "sum": 999,
    "events": "507.0KiB",
    "time": "01:06"
}
];

const result = data.reduce((acc, value, key) => {
  const object = acc.find(item => item.time === value.time);

  if(object) {
    if (Number.isInteger(object[value.app])) {
      object[value.app] += value.sum  
    } else {
      object[value.app] = value.sum
    }
    
    return acc;
  }

  acc.push({
    time: value.time,
    [value.app]: value.sum
  });

  return acc;
}, []);

console.log(result);

Upvotes: 1

Niek Nijland
Niek Nijland

Reputation: 772

const data = [
    {
        "eventdate": 1561334400000,
        "app": "cloudmark-desktop",
        "sum": 2970,
        "events": "2.9KiB",
        "time": "00:06"
    },
    {
        "eventdate": 1561334400000,
        "app": "dns",
        "sum": 519169,
        "events": "507.0KiB",
        "time": "00:06"
    },
    {
        "eventdate": 1561334400000,
        "app": "cloudmark-desktop",
        "sum": 999,
        "events": "507.0KiB",
        "time": "01:06"
    },
    {
        "eventdate": 1561334400000,
        "app": "dns",
        "sum": 999,
        "events": "507.0KiB",
        "time": "01:06"
    }
];

const formattedData = data.reduce((acc, a) => {
  const timeExists = acc.findIndex(b => a.time === b.time);

  if(timeExists > -1) {
    const copy = [...acc];
    copy[timeExists] = {
      ...copy[timeExists],
      [a.app]: a.sum
    }
    return copy
  } else {
    return [
      ...acc,
      {
        time: a.time,
        [a.app]: a.sum	
      }
    ]
  }
}, []);

console.log(formattedData);

Try this. Probably the first part of the if statement deserves some love though.

Upvotes: 1

user7290573
user7290573

Reputation: 1330

Here's one way, albeit a bit ugly:

var output = {};
var data   = [
    {
        "eventdate": 1561334400000,
        "app": "cloudmark-desktop",
        "sum": 2970,
        "events": "2.9KiB",
        "time": "00:06"
    },
    {
        "eventdate": 1561334400000,
        "app": "dns",
        "sum": 519169,
        "events": "507.0KiB",
        "time": "00:06"
    },
    {
        "eventdate": 1561334400000,
        "app": "cloudmark-desktop",
        "sum": 999,
        "events": "507.0KiB",
        "time": "01:06"
    },
    {
        "eventdate": 1561334400000,
        "app": "dns",
        "sum": 999,
        "events": "507.0KiB",
        "time": "01:06"
    }
];

for (var i = 0; i < data.length; i++) {
    var d = data[i];

    if (output[d["time"]]) {
        output[d["time"]][d["app"]] = d["sum"];
    } else {
        output[d["time"]] = {
            time: d["time"],
            [d["app"]]: d["sum"]
        }
    }
}

console.log(Object.values(output));

Upvotes: 1

Related Questions