user9454269
user9454269

Reputation:

How to reformat a JSON array into another format "grouping" based on different keys

Question: How can I reformat this JSON array by "grouping" via different keys, using ReactJS?

I have a JSON array as :

[ 
    {Product: "Shoes", Sold: 5, Bought : 0, Reversed : 2} , 
    {Product: "Table", Sold: 2, Bought : 0, Reserved : 4} 
]

The reason for this is the data type I'm working with, and on realizing I need to visualize this data in a different way (due to one of the graph packages I am using) I need to structure this data as:

[
  {
    Status: "Sold",
    Shoes : 5,
    Table : 2
  } , 
  { 
    Status: "Bought",
    Shoes : 0,
    Table : 0
  } , 
  {
    Status: "Reserved",
    Shoes : 2, 
    Table : 4
  } 
]

So I'm grouping the data into the keys other than Product, and then the keys after this are Product with the Value being the Product and it's "status".

Frankly, I am at a complete loss as to what to do, as I'm thinking the code required to generate this would be quite convoluted, so I'm very open to know if this just is too much work.

Upvotes: 0

Views: 61

Answers (3)

dwjohnston
dwjohnston

Reputation: 11812

You can do this using the Array.reduce function. (Actually, two reduce functions).

Here's an extensible solution that allows for other statuses.

Note that I changed everything to lowercase, as is standard convention.

const items = [ 
    {product: "Shoes", sold: 5, bought : 0, reserved : 2} , 
    {product: "Table", sold: 2, bought : 0, reserved : 4} 
]

//We declare the status types here. 
const keys = ["sold", "bought", "reserved"]; 

// Just create the initial 'statuses' array. 
function initAcc(keys) {
    return keys.map((key) => {
        return {
                status: key            
        }
    }); 
}

//Here we are iterating over each item, getting it to return a single accumulator array each time. 
const newItems = items.reduce((acc, cur) => {
   return addItemToAccumulator(acc, cur); 
}, initAcc(keys)); 

console.log(newItems); 

// This function maps of the accumulator array (ie. over each status). 
function addItemToAccumulator(acc, item) {
    return acc.reduce((acc, statusLine) => {

        //Find the count from the existing status if it exists, 
        //Add the current items count for that status to it. 
        const itemCount = item[statusLine.status]  + (statusLine[item.product] || 0);   


        //Return a modified status, with the new count for that product
        return [
          ...acc, 
          {
              ...statusLine, 
              [item.product]: itemCount
          }
        ]; 
    }, []);                
}

Upvotes: 1

theFlyingCoder
theFlyingCoder

Reputation: 119

Lets just do a simple loop function and create a couple objects to clearly solve the problem here:

const data = [YOUR_INITIAL_ARRAY];
let Sold, Bought, Reserved = {};

data.forEach(({Product, Sold, Bought, Reserved})=> {
  Sold[Product] = Sold;
  Bought[Product] = Bought;
  Reservered[Product] = Reserved;
});
let newArray = [Sold, Bought, Reserved];

I think you can see where this is going ^ I see a few others have given complete answers, but try and go for the clear understandable route so it makes sense.

All you have to do after this is set the status which i'd do off an enum and you are good

Upvotes: -1

keikai
keikai

Reputation: 15146

const data = [
  {
    Product: "Shoes",
    Sold: 5,
    Bought : 0,
    Reserved : 2
  } , {
    Product: "Table",
    Sold: 2,
    Bought : 0,
    Reserved : 4
  }
];
let resultData = [];
Object.keys(data[0]).forEach((key, idx) => {
  if (idx !== 0) {
      let resultUnit = {
        Status: key, 
      };
      data.forEach(item => {
        return resultUnit = {
          ...resultUnit,
          [item.Product]: item[key],
        }
      })
      resultData.push(resultUnit);
  }
})
console.log(resultData);
// 0: {Status: "Sold", Shoes: 5, Table: 2}
// 1: {Status: "Bought", Shoes: 0, Table: 0}
// 2: {Status: "Reserved", Shoes: 2, Table: 4}

Upvotes: 1

Related Questions