1

This might be a basic issue that I am unable to fix. I have an initial array values received from an API something like this:

const primaryArray = [
    {
    startDate: '01-01-2021',
    endDate: '11-01-2021',
    refs: [
        {
        refId: "FL013",
                year: "2021"
      }
    ]
  },
  {
    startDate: '01-02-2021',
    endDate: '28-02-2021',
    refs: [
        {
        refId: "FL013",
                year: "2021"
      }
    ]
  },
  {
    startDate: '03-05-2020',
    endDate: '10-06-2020',
    refs: [
        {
        refId: "FL013",
                year: "2020"
      }
    ]
  },
  {
    startDate: '25-03-2019',
    endDate: '25-04-2019',
    refs: [
        {
        refId: "FL013",
                year: "2019"
      }
    ]
  }
];

Since two of the objects of year 2021 share the same reference key as 'FL013', I want to convert them into the form as this with all objects separated out from array:

{
    2021: { 
    'year': 2021, 
    'refIds': ['FL013', 'FL013'], 
    'duration': { 
      'FL013': [
        {
          startDate: '01-01-2021',
          endDate: '11-01-2021'
        }, 
        {
          startDate: '01-02-2021',
          endDate: '28-02-2021',
        }
       ]
     }
    }
},
{
    2020: { year: 2020, 'refIds': ['FL013'], 'duration': { 'FL013': {
                                               startDate: '03-05-2020',
                                               endDate: '10-06-2020',
                                             }
          }
},
{
    2019: { year: 2019, 'refIds': ['FL013'], 'duration': { 'FL013': {
                                               startDate: '25-03-2019',
                                               endDate: '25-04-2019',
                                             }
          }
}

I tried to use JS reduce for the same, but the array creation for year with two dates objects keeps throwing me an error.

This is what I tried to achieve so far:

const flatArray = primaryArray && primaryArray.reduce(
(acc, {startDate, endDate, refs}, currentIndex) => {

  const year = refs && refs[0] && refs[0].year;
  const refId = refs && refs[0] && refs[0].refId;
            
   if (
        year &&
        refId &&
        startDate &&
        endDate &&
        !Object.prototype.hasOwnProperty.call(acc, year)
      ) {
           acc[year] = {
               year,
               refIds: [refId],
               duration: {
                           [refId]: {
                             startDate,
                             endDate,
                         },
               },
           };
        } else {
            if (year) {
                acc[year].refIds.push(refId);
                acc[year]['duration'][refId] = {
                  startDate,
                  endDate,
                };
              }
            }
   return acc;
},{});

I modified my above code using two approaches to achieve the exact result: first, to push the dates object as received in the accumlator

acc[year]['duration'][refId].push({ startDate, endDate }). 

This throws error:

Uncaught TypeError: acc[year].duration[refId].push is not a function

or second, direct apply [] notation (which I understand is not applicable).

Here is the working link for the same: https://onecompiler.com/javascript/3wwzz3f4s

Any help to resolve the same, highly appreciated.

2
  • Your playcode link doesn't have any code... but when I tested this on my machine the output looked good and no errors... Commented May 9, 2021 at 17:13
  • @JohnTyner This works but does not return me the format I require. I have updated my working code link Commented May 9, 2021 at 17:22

3 Answers 3

1

You can do something like this with Array.prototype.reduce():

const primaryArray = [
    {
    startDate: '01-01-2021',
    endDate: '11-01-2021',
    refs: [
        {
        refId: "FL013",
                year: "2021"
      }
    ]
  },
  {
    startDate: '01-02-2021',
    endDate: '28-02-2021',
    refs: [
        {
        refId: "FL013",
                year: "2021"
      }
    ]
  },
  {
    startDate: '03-05-2020',
    endDate: '10-06-2020',
    refs: [
        {
        refId: "FL013",
                year: "2020"
      }
    ]
  },
  {
    startDate: '25-03-2019',
    endDate: '25-04-2019',
    refs: [
        {
        refId: "FL013",
                year: "2019"
      }
    ]
  }
];

const res = primaryArray.reduce((acc, {refs, startDate, endDate}) => {
  if(!acc[refs[0].year]) {   
    acc[refs[0].year] = {
      year: refs[0].year,
      refIds: [refs[0].refId],
      duration: {
        [refs[0].refId]: {
          startDate: startDate,
          endDate: endDate
        }
      }
    }
  } else {
    acc[refs[0].year].refIds.push(refs[0].refId);
    acc[refs[0].year].duration = {
      [refs[0].refId]: [
        {...acc[refs[0].year].duration[refs[0].refId]},
        {
          startDate: startDate,
          endDate: endDate
        }
      ]

    }
  }

  return acc;
}, {})

console.log(res);

Sign up to request clarification or add additional context in comments.

Comments

1

Another option is to test to see if it's already an array, if not then create it. typeof acc[year]['duration'][refId] !== '[object Array]'

const flatArray = primaryArray && primaryArray.reduce(
(acc, {startDate, endDate, refs}, currentIndex) => {

  const year = refs && refs[0] && refs[0].year;
  const refId = refs && refs[0] && refs[0].refId;


            
   if (
        year &&
        refId &&
        startDate &&
        endDate &&
        !Object.prototype.hasOwnProperty.call(acc, year)
      ) {
           acc[year] = {
               year,
               refIds: [refId],
               duration: {
                           [refId]: {
                             startDate,
                             endDate,
                         },
               },
           };
        } else {
            if (year) {
                acc[year].refIds.push(refId);
                if (acc[year]['duration'][refId] && typeof acc[year]['duration'][refId] !== '[object Array]') {
                    acc[year]['duration'][refId] = [acc[year]['duration'][refId]]
                }

                acc[year]['duration'][refId].push({
                  startDate,
                  endDate,
                })
              }
            }
   return acc;
},{});

Comments

1

const primaryArray = [{
    startDate: '01-01-2021',
    endDate: '11-01-2021',
    refs: [{
      refId: 'FL013',
      year: '2021',
    }, ],
  },
  {
    startDate: '01-02-2021',
    endDate: '28-02-2021',
    refs: [{
      refId: 'FL013',
      year: '2021',
    }, ],
  },
  {
    startDate: '03-05-2020',
    endDate: '10-06-2020',
    refs: [{
      refId: 'FL013',
      year: '2020',
    }, ],
  },
  {
    startDate: '25-03-2019',
    endDate: '25-04-2019',
    refs: [{
      refId: 'FL013',
      year: '2019',
    }, ],
  },
];

const result = primaryArray.reduce((acc, cur) => {
  const {
    startDate,
    endDate,
    refs: [{
      refId,
      year
    }],
  } = cur;
  const entry = acc[year];
  const yearExistsAlready = entry !== undefined;
  if (yearExistsAlready) {
    entry.refIds.push(refId);
    const duration = entry.duration[refId];
    const durationExistsAlready = duration !== undefined;
    if (durationExistsAlready) entry.duration[refId].push({
      startDate,
      endDate
    });
    else entry.duration = {
      refId: {
        startDate,
        endDate
      }
    };
  } else {
    acc[year] = {
      year,
      refIds: [refId],
      duration: {
        [refId]: [{
          startDate,
          endDate
        }],
      },
    };
  }
  return acc;
}, {});
console.log(result)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.