skip to Main Content

I have an Array of objects, I want to group the data by Project Name and Employee Name and, in the case of an existing project and employee, add the hours.

projects = [
    {
      "project": { "id": 1, "name": "Mars Rover" },
      "employee": { "id": 1, "name": "Mario" },
      "date": "2021-08-26T22:00:00.000Z",
      "hours": 5
    },
    {
      "project": { "id": 2, "name": "Manhattan" },
      "employee": { "id": 2, "name": "Giovanni" },
      "date": "2021-08-30T22:00:00.000Z",
      "hours": 3
    },
    {
      "project": { "id": 1, "name": "Mars Rover" },
      "employee": { "id": 1, "name": "Mario" },
      "date": "2021-08-31T22:00:00.000Z",
      "hours": 3
    },
    {
      "project": { "id": 1, "name": "Mars Rover" },
      "employee": { "id": 3, "name": "Lucia" },
      "date": "2021-08-31T22:00:00.000Z",
      "hours": 3
    },
    {
      "project": { "id": 2, "name": "Manhattan" },
      "employee": { "id": 1, "name": "Mario" },
      "date": "2021-08-26T22:00:00.000Z",
      "hours": 2
    },
    {
      "project": { "id": 2, "name": "Manhattan" },
      "employee": { "id": 2, "name": "Giovanni" },
      "date": "2021-08-31T22:00:00.000Z",
      "hours": 4
    }
  ]
}

This is how I want the data to be after carrying out the sum

projects = [
  {project: "Mars Rover", employee: "Mario" hours: 8},
  {project: "Mars Rover", employee: "Lucia" hours: 3},
  {project: "Manhattan", employee: "Giovanni" hours: 7},
  {project: "Manhattan", employee: "Mario" hours: 2}
]

In practice I want to group the data by Project Name and Employee Name and, in the case of an existing project and employee, add the hours.
This is the code I wrote:

let newRows = [];

  projects.forEach((element) => {
    if (newRows.length === 0) {
      newRows.push(element);
    } else {
      const index = newRows.findIndex(
        (project) =>
          project.project.id === element.project.id &&
          project.employee.id === element.employee.id
      );
      if (index > -1) {
        newRows[index].hours += element.hours;
      } else {
        newRows.push(element);
      }
    }
  });

It works, but I get a bug. Basically, every time I write code in that file, the total hours on the screen stretch by themselves, then I reload the page and everything goes back to the way it was.

This is an example

enter image description here

2

Answers


  1. First you can do the following:

    let hours = {};
    projects.map((p) => {
      if (hours[p.project.name]) {
        if (hours[p.project.name][p.employee.name])
          hours[p.project.name][p.employee.name] += p.hours;
        else hours[p.project.name][p.employee.name] = p.hours;
      } else {
        hours[p.project.name] = { [p.employee.name]: p.hours };
      }
    });
    

    In the case of your projects, hours will look like this:
    enter image description here

    Once you have the total hours by employee by project, you can for sure format it as you want, for instance you requested it like this:

    let projectsHours = [];
    Object.keys(hours).map((projectName) => {
      Object.keys(hours[projectName]).map((employeeName) => {
        projectsHours.push({
          project: projectName,
          employee: employeeName,
          hours: hours[projectName][employeeName]
        });
      });
    });
    

    Complete code to run here:

    let projects = [
      {
        project: { id: 1, name: "Mars Rover" },
        employee: { id: 1, name: "Mario" },
        date: "2021-08-26T22:00:00.000Z",
        hours: 5
      },
      {
        project: { id: 2, name: "Manhattan" },
        employee: { id: 2, name: "Giovanni" },
        date: "2021-08-30T22:00:00.000Z",
        hours: 3
      },
      {
        project: { id: 1, name: "Mars Rover" },
        employee: { id: 1, name: "Mario" },
        date: "2021-08-31T22:00:00.000Z",
        hours: 3
      },
      {
        project: { id: 1, name: "Mars Rover" },
        employee: { id: 3, name: "Lucia" },
        date: "2021-08-31T22:00:00.000Z",
        hours: 3
      },
      {
        project: { id: 2, name: "Manhattan" },
        employee: { id: 1, name: "Mario" },
        date: "2021-08-26T22:00:00.000Z",
        hours: 2
      },
      {
        project: { id: 2, name: "Manhattan" },
        employee: { id: 2, name: "Giovanni" },
        date: "2021-08-31T22:00:00.000Z",
        hours: 4
      }
    ];
    
    let hours = {};
    projects.map((p) => {
      if (hours[p.project.name]) {
        if (hours[p.project.name][p.employee.name])
          hours[p.project.name][p.employee.name] += p.hours;
        else hours[p.project.name][p.employee.name] = p.hours;
      } else {
        hours[p.project.name] = { [p.employee.name]: p.hours };
      }
    });
    
    let projectsHours = [];
    Object.keys(hours).map((projectName) => {
      Object.keys(hours[projectName]).map((employeeName) => {
        projectsHours.push({
          project: projectName,
          employee: employeeName,
          hours: hours[projectName][employeeName]
        });
      });
    });
    
    console.log(projectsHours);
    Login or Signup to reply.
  2. You can do this using map and reduce

    const result = projects.map(el => {
        return { project: el.project.name, employee: el.employee.name, hours: el.hours};
    }).reduce((acc, elem) => {
       const accIndex = acc.findIndex(ai => ai.project === elem.project && ai.employee === elem.employee);
       if (accIndex < 0) {
         acc.push(elem);
       } else {
         acc[accIndex].hours += elem.hours;
       }
       return acc;
    }, []);
    console.log(result);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search