0

I have the following data objects in a list within in my React project:

{projectId: "11111", startTime: "Mon May 11 2020 19:19:07", duration: "15"}
{projectId: "22222", startTime: "Mon May 11 2020 19:24:07", duration: "45"}
{projectId: "11111", startTime: "Mon May 11 2020 19:45:07", duration: "15"}
{projectId: "11111", startTime: "Tue May 12 2020 11:00:07", duration: "30"}
{projectId: "22222", startTime: "Tue May 12 2020 12:19:07", duration: "15"}

I want to be able to group and sum this data by Date and ProjectId so i would expect the following output:

{projectId: "11111", Date: "Mon May 11 2020", TotalDuration: "30"}
{projectId: "22222", Date: "Mon May 11 2020", TotalDuration: "45"}
{projectId: "11111", Date: "Tue May 12 2020", TotalDuration: "30"}
{projectId: "22222", Date: "Tue May 12 2020", TotalDuration: "15"}

I am new to ReactJS and can not seem to find a solution to do this.

4 Answers 4

1

You can use reduce and filter for group your items:

const items = [{projectId: "11111", startTime: "Mon May 11 2020 19:19:07", duration: "15"},
{projectId: "22222", startTime: "Mon May 11 2020 19:24:07", duration: "45"},
{projectId: "11111", startTime: "Mon May 11 2020 19:45:07", duration: "15"},
{projectId: "11111", startTime: "Tue May 12 2020 11:00:07", duration: "30"},
{projectId: "22222", startTime: "Tue May 12 2020 12:19:07", duration: "15"}]

const trimTime = (dateTime) => dateTime.split(' ').splice(0, 4).join(' ')

const groupItems = items.reduce((acc,rec) => {
  const itemsInAcc = acc.filter(a=>a.projectId === rec.projectId && a.startTime === trimTime(rec.startTime))
  if (itemsInAcc.length > 0) {
    itemsInAcc[0].duration = (+itemsInAcc[0].duration) + (+rec.duration)
  }
  else {
    acc = [...acc, {...rec, startTime: trimTime(rec.startTime)}]
  }
  return acc
}, [])
Sign up to request clarification or add additional context in comments.

Comments

1

You can do this, though I'd recommend using an ISO-format datetime string instead of this format for startTime, since the Date constructor is not guaranteed to be able to parse this format in every implementation.

const data = [
  {projectId: "11111", startTime: "Mon May 11 2020 19:19:07", duration: "15"},
  {projectId: "22222", startTime: "Mon May 11 2020 19:24:07", duration: "45"},
  {projectId: "11111", startTime: "Mon May 11 2020 19:45:07", duration: "15"},
  {projectId: "11111", startTime: "Tue May 12 2020 11:00:07", duration: "30"},
  {projectId: "22222", startTime: "Tue May 12 2020 12:19:07", duration: "15"}
];

const updateOrCreate = (map, key, update, create) => map.set(
  key,
  update(map.has(key) ? map.get(key) : create())
);

const sums = [
  ...data.map(
    o => ({ ...o, Date: new Date(o.startTime).toDateString() })
  ).reduce(
    (outer, o) => updateOrCreate(
      outer,
      o.Date,
      inner => updateOrCreate(
        inner,
        o.projectId,
        sum => +o.duration + sum,
        () => 0
      ),
      () => new Map()
    ),
    new Map()
  )
].flatMap(
  ([Date, projects]) => [...projects].map(
    ([projectId, duration]) => ({
      projectId, Date, TotalDuration: `${duration}`
    })
  )
);

console.log(sums);

Comments

1

you can try to group your data by productId + date without the time part, using Array.reduce():

const data = [
  {projectId: "11111", startTime: "Mon May 11 2020 19:19:07", duration: "15"},
  {projectId: "22222", startTime: "Mon May 11 2020 19:24:07", duration: "45"},
  {projectId: "11111", startTime: "Mon May 11 2020 19:45:07", duration: "15"},
  {projectId: "11111", startTime: "Tue May 12 2020 11:00:07", duration: "30"},
  {projectId: "22222", startTime: "Tue May 12 2020 12:19:07", duration: "15"}
];

const result = data.reduce((res, curr) => {
  // remove time
  const date = curr.startTime.substr(0, curr.startTime.length - 9);
  // build the key (productId + date without the time part)
  const key = `${curr.projectId}_${date}`;
  res[key] = res[key] || {
    projectId: curr.projectId,
    Date: date,
    TotalDuration: "0"
  };
  // sum durations as integers and convert the sum back to string
  res[key].TotalDuration = (+res[key].TotalDuration + +curr.duration) + '';
  return res;
}, {});

// print only values
console.log(Object.values(result));

BTW: the solution is in plain JS (nothing React specific)

Comments

0

You can do this:

const groupedDataObj = {};

for(let entry of oridinalData) {
  const regexDate = /^([A-Za-z]){3} ([A-Za-z]){3} \d{2} \d{4}/;
  const key = entry.projectId + '||' + entry.startTime.split(regexDate)[0]
  if(!groupedDataObj.hasOwnProperty(key)) {
    groupedDataObj[key] = { totalDuration: 0 };
  }
  groupedDataObj[key].totalDuration += +entry.TotalDuration;
}

const groupedData = Object.keys(groupedDataObj).map(key => {
  const splittedKey = key.split('||');
  const productId = splittedKey[0];
  const Date = splittedKey[1];
  return {
    productId,
    Date,
    TotalDuration: groupedDataObj[key].totalDuration
  };
});

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.