Search code examples
javascriptnode8.4

Array of objects manipulation


I feel that im close to the answer but I am not outputting exactly the format Im looking for

So, I have this array of objects:

const data = [
{email: '[email protected]', amount: '30', date: '2018-12'},
{email: '[email protected]', amount: '30', date: '2018-11'},
{email: '[email protected]', amount: '30', date: '2018-10'},

{email: '[email protected]', amount: 0,    date: '2018-12'},
{email: '[email protected]', amount:'30',  date: '2018-11'},
{email: '[email protected]', amount:'30',  date: '2018-10'},
{email: '[email protected]', amount:'30',  date: '2018-09'},
{email: '[email protected]', amount:'25',  date: '2018-08'},
{email: '[email protected]', amount:'25',  date: '2018-08'},]

As you can see in the data set there are repeated emails as well as duplicate objects like the last 2 in the data set.

I want to turn it into this array of objects:

const data = [
{
    email: '[email protected]',
    '2018-12': '30',
    '2018-11': '30',
    '2018-10': '30', 
    '2018-09': 0, 
    '2018-08': 0, 
    '2018-07': 0, 
    '2018-06': 0, 
    '2018-05': 0, 
    '2018-04': 0, 
    '2018-03': 0, 
    '2018-02': 0, 
    '2018-01': 0, 
    '2017-12': 0, 
},
{
    email: '[email protected]',
    '2018-12':0,
    '2018-11':'30',
    '2018-10':'30',
    '2018-09':'30',
    '2018-08':'25',
    '2018-07': 0,
    '2018-06': 0,
    '2018-05': 0,
    '2018-04': 0,
    '2018-03': 0,
    '2018-02': 0,
    '2018-01': 0,
    '2017-12': 0,
}]

The output has a range of dates from 2017-12 to 2018-12 and the value for the date key is the amount for that specific date, else if the date is not found on the object the value for that date defaults to 0

At the moment Im playing with the reduce() function using something like this:

let result = data.reduce((acc, {email, date, amount}) => {
    acc.email = email
    acc[date] = amount
    return acc;
}, {});

result is only returning the last email with not exactly the range of dates Im looking for.

Thanks in advance for your help.


Solution

  • Reduce into an object indexed by each email, creating the inner object explicitly if the [email] property doesn't exist on the accumulator yet. Once you're sure the object exists, you can assign to acc[email][date], and at the end, use Object.values to transform the object back into the desired array format:

    const data = [
    {email: '[email protected]', amount: '30', date: '2018-12'},
    {email: '[email protected]', amount: '30', date: '2018-11'},
    {email: '[email protected]', amount: '30', date: '2018-10'},
    
    {email: '[email protected]', amount: 0,    date: '2018-12'},
    {email: '[email protected]', amount:'30',  date: '2018-11'},
    {email: '[email protected]', amount:'30',  date: '2018-10'},
    {email: '[email protected]', amount:'30',  date: '2018-09'},
    {email: '[email protected]', amount:'25',  date: '2018-08'},
    {email: '[email protected]', amount:'25',  date: '2018-08'},]
    
    let result = data.reduce((acc, {email, date, amount}) => {
      if (!acc[email]) acc[email] = { email };
      acc[email][date] = amount;
      return acc;
    }, {});
    console.log(Object.values(result));