skip to Main Content

I’m prepping backend data for a table and want to get it set in a way so I can map out the table rows. The headers for the table is based on the date range that is used to query the data (always a 6 month spread), which I then compare and do a merge with the data to set up the initial objects, but then I need to compare with another array from the backend to make the row complete.

Here is the headers and data arrays:

const headers = [ "2022-7", "2022-8", "2022-9", "2022-10", "2022-11", "2022-12" ]


const data = [
{
        "planDetails": {
            "goals": [
                {
                    "title": "Budget",
                    "frequency": 4
                },
                {
                    "title": "clean",
                    "frequency": 6
                }
            ]
        },
        "setVisits": [
            {
                "goals": [
                    {
                        "k": "clean",
                        "v": 2
                    },
                    {
                        "k": "Budget",
                        "v": 2
                    }
                ],
                "date": "2022-9"
            },
            {
                "goals": [
                    {
                        "k": "clean",
                        "v": 2
                    },
                    {
                        "k": "Budget",
                        "v": 2
                    }
                ],
                "date": "2022-10"
            },
            {
                "goals": [
                    {
                        "k": "Budget",
                        "v": 1
                    },
                    {
                        "k": "clean",
                        "v": 2
                    },
                ],
                "date": "2022-8"
            }
        ]
    }
]

And then the steps I’ve taken:

const output = data.shift()
console.log(output
)

const newHeader = headers.map(i => new Date(i).toISOString())
/* console.log(newHeader) */

const visits = output.setVisits.map(i => { return {date: new Date(i.date).toISOString(), goals: i.goals}})
/* console.log(visits) */

const result = newHeader.map(item => {
/* console.log(item) */
  
    const info = visits.find(detail => detail.date === item);
    /* console.log(info) */
if (info) {
    return {
        date: item,
        goals: info.goals
    }
    } else {
    return {
        date: item,
      goals: 0
    }
    }
})
result.sort((a,b) => a.date > b.date)


let finalArr = []

const next = output.planDetails.goals.forEach(i => {
    let newObj = {}
  /* console.log(i) */
 if ( result.find(a => a.goals.k === i.title)) {
        newObj = {
        goal: i.title,
      frequency: i.frequency,
      elem1: {
        date: a[0].date,
        count: a[0].goals.v
      },
      elem2: {
        date: a[1].date,
        count: a[1].goals.v
      }
    } 
/* I've only put to the 2nd index of 6 to try and get the proof of concept down before mapping the rest */
 } else if (!result.find(a => a.goals.k === i.title)) {
        newObj = {
        goal: i.title,
      frequency: i.frequency,
      elems: {
        date: a[0].date,
        count: 0
      }
    }
 }
  finalArr.push(newObj)
})

console.log(finalArr)

Its that last step that is off and javascript makes my head spin. I’m pretty certain theres a simple way to compare the 2 fields of the objects and map that out, providing a 0 if there is no matching field, but I’m getting no where.

My ideal final array would look like:

[
{goal: 'Budget', frequency: 4, elem1: {date: "2022-7", count: 1}, elem2: {date: "2022-8", count: 3}, elem3: {date: "2022-9", count: 0}, etc.}
{goal: 'clean', frequency: 2, elem1: {date: "2022-7", count: 1}, elem2: {date: "2022-8", count: 0}, elem3: {date: "2022-9", count: 2}, etc.}

]

Thanks in advance for any input, here’s a link to the fiddle: https://jsfiddle.net/joznox/rwyL928a/45/

2

Answers


  1. You could first create a lookup table for the frequency of each goal for a particular date using Array#reduce. Then, the final result can be created with Array#map.

    const headers=["2022-7","2022-8","2022-9","2022-10","2022-11","2022-12"],data=[{planDetails:{goals:[{title:"Budget",frequency:4},{title:"clean",frequency:6}]},setVisits:[{goals:[{k:"clean",v:2},{k:"Budget",v:2}],date:"2022-9"},{goals:[{k:"clean",v:2},{k:"Budget",v:2}],date:"2022-10"},{goals:[{k:"Budget",v:1},{k:"clean",v:2},],date:"2022-8"}]}];
    
    const o = data.shift(); // or data[0] to not mutate data
    const lookup = o.setVisits.reduce((acc, {date, goals}) => {
       goals.forEach(({k, v}) => (acc[date] ??= {})[k] = (acc[date][k] ?? 0) + v);
       return acc;
    }, {});
    const res = o.planDetails.goals.map(({title: goal, frequency}) => 
      ({goal, frequency, ...Object.fromEntries(headers
        .map((date, i) => [`elem${i+1}`, {date, count: lookup[date]?.[goal] ?? 0}]))}));
    console.log(res);
    .as-console-wrapper{max-height:100%!important}
    Login or Signup to reply.
  2. Another solution may be to shape your data first, taking advantage of object indexes to aggregate the data.

    const fields = headers.reduce((a,d)=>{
        a[d] = 0;
        return a;
      },{});
    
    let final= {};
    for(let visit of data.pop().setVisits){
      let date = new Date(visit.date)
        .toISOString()
        .substr(0,7)
        .split('-')
        .map(d=>Number.parseInt(d))
        .join('-')
        ;
      for(let goal of visit.goals){
        let v = goal.v;
        goal = goal.k;
        final[goal] ??= {
          frequency:0,
          fields:Object.assign({},fields)
        };
        final[goal].frequency+=v;
        final[goal].fields[date]+=v;
      }
    }
    console.log(final);
    

    Then once the data is aggregated, shape it for your output.

    let finalArr = Object.entries(final).map(d=>{
      let row = Object.entries(d[1].fields)
        .sort(d=>{ return new Date(d[0])-new Date(d[1]); })
        .map (d=>{ return {date: d[0], count: d[1]}; })
        .reduce((a,d,i)=>{ a[`elem${i+1}`] = d; return a;}, {})
        ;
      row.goal = d[0];
      row.frequency = d[1].frequency;
      return row;
    });
    console.log(finalArr);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search