1

I have an array of objects like this

  data = [
    {
      Category_Name: "Furniture",
      Status_Name: "Available",
      Count: 1
    },
    {
      Category_Name: "License",
      Status_Name: "Available",
      Count: 3
    },
    {
      Category_Name: "Laptop",
      Status_Name: "Good Condition",
      Count: 1
    },
    {
      Category_Name: "Laptop",
      Status_Name: "Good Condition",
      Count: 1
    },
    {
      Category_Name: "Vehicle",
      Status_Name: "Requested",
      Count: 2
    },
    {
      Category_Name: "Furniture",
      Status_Name: "Good Condition",
      Count: 1
    }
  ];

I am trying to, first, group by same Category_Name and sum count values which I made it right, and second create a new array called status inside returned object which will count by status names (Available, Good Condition and Requested). So the final result will be like

[
  {
    Category_Name: "Furniture",
    total: 2,
    status: [
      {
        Available: 1,
        Good_Condition: 1,
        Requested: 0
      }
    ]
  },
  {
    Category_Name: "License",
    total: 3,
    status: [
      {
        Available: 3,
        Good_Condition: 0,
        Requested: 0
      }
    ]
  },
  {
    Category_Name: "Laptop",
    total: 2,
    status: [
      {
        Available: 0,
        Good_Condition: 2,
        Requested: 0
      }
    ]
  },
  {
    Category_Name: "Vehicle",
    total: 2,
    status: [
      {
        Available: 0,
        Good_Condition: 0,
        Requested: 2
      }
    ]
  }
];

I can only solve up to getting total

{
    Category_Name: "Furniture",
    total: 2,
},
..

with

        data.forEach(function(d) {
          if (holder.hasOwnProperty(d.Category_Name)) {
            holder[d.Category_Name] =
              holder[d.Category_Name] + d.Count;
          } else {
            holder[d.Category_Name] = d.Count;
          }
        });


        for (var prop in holder) {
          obj2.push({ Category_Name: prop, total: holder[prop] });
        }

and I am having issue getting status array, If someone could help me , I would very much appreciated, thanks.

Kaung Khant Zaw
  • 1,508
  • 3
  • 19
  • 31

2 Answers2

2

You can use an array reduce and do this, I have made the status an object instead of an array, you can do that if required with a small change.

If the 0 counts for status are not required you can simplify the code by dynamically populating the status counts

const reducer = (a, c) => {
  const item = a.find((x) => x.Category_Name === c.Category_Name);
  const status = c["Status_Name"].replace(' ', '_');
  if (item) {
    item.Total += c.Count;
    item.status[status] += c.Count;
  } else {
    const newItem = {
      Category_Name: c.Category_Name,
      Total: c.Count,
      status: {
        Available: 0,
        Good_Condition: 0,
        Requested: 0
      }
    };
    newItem.status[status] += c.Count;
    a.push(newItem);
  }
  return a;
};

const data = [
  {
    Category_Name: "Furniture",
    Status_Name: "Available",
    Count: 1
  },
  {
    Category_Name: "License",
    Status_Name: "Available",
    Count: 3
  },
  {
    Category_Name: "Laptop",
    Status_Name: "Good Condition",
    Count: 1
  },
  {
    Category_Name: "Laptop",
    Status_Name: "Good Condition",
    Count: 1
  },
  {
    Category_Name: "Vehicle",
    Status_Name: "Requested",
    Count: 2
  },
  {
    Category_Name: "Furniture",
    Status_Name: "Good Condition",
    Count: 1
  }
];


console.log(data.reduce(reducer, []));
Guruparan Giritharan
  • 15,660
  • 4
  • 27
  • 50
1

You can probably shorten this but I've purposely made it verbose so you can see what's going on. I'm first looping through data and putting the results in an object named totals, in which keys are Category_Name. This makes it easy to find a given category name, rather than having to search through an array each time.

Once totals has been created, I effectively remove the keys and turn it into an array with Object.values(totals), and store the results in results.

let totals = {};
  
data.forEach( function(row) {
    if ( totals[row.Category_Name] ) {
        if ( totals[ row.Category_Name ].status[0][ row.Status_Name ] ) {
            totals[ row.Category_Name ].status[0][ row.Status_Name ]++;
        } else {
            totals[ row.Category_Name ].status[0][ row.Status_Name ] = 1;
        }
        totals[ row.Category_Name ].total += row.Count;
    } else {
        totals[row.Category_Name] = {
            Category_Name: row.Category_Name,
            total: row.Count,
            status: [ { [row.Status_Name]: 1 } ] // https://stackoverflow.com/a/2274327/378779
        }
    }
});

let results = Object.values(totals);

console.log(results);
kmoser
  • 8,780
  • 3
  • 24
  • 40
  • Thanks for the help first of all ! However there is one thing I noticed missing, I also want to set default values in an array for other status names if they don't have counts so it will be `Available: 1`,`Good_Condition: 0`, `Requeted: 0`. – Kaung Khant Zaw Nov 05 '20 at 08:03
  • You can do that easily: loop through `results`, and for each element look at its status array, and add any missing status names and their default values. – kmoser Nov 06 '20 at 04:23