Home > Mobile >  Format JSON, order by key group using vanilla js
Format JSON, order by key group using vanilla js

Time:03-25

I people, i need help , i dont know how to handle the object to get what I need using vanilla. I need group by "type" for each "elem", and sum price and discount values, and return them in an array. I would appreciate if someone could explain to me how to approach the transformation.

I have this object

{
        "w_elem": [
            {
                "elem": [
                    {"type": "type_a","price": "100","discount": "10"},
                    {"type": "type_b","price": "120","discount": "12"},
                    {"type": "type_a","price": "165","discount": "10"}
                ],
                "user": "1001",
                "userType": "A"
            },
            {
                "elem": [
                    {"type": "type_a","price": "50","discount": "5"},
                    {"type": "type_b","price": "15","discount": "0"}
                ],
                "user": "1011",
                "userType": "B"
            },
            {
                "elem": [
                    {"type": "type_a","price": "20","discount": "5"},
                    {"type": "type_b","price": "15","discount": "0"}
                ],
                "user": "1011",
                "userType": "B"
            }
        ]
    }

Imust return the following array

    [
      {"type": "type_a","price": "335","discount":"30"},
      {"type":"type_b","price": "150","discount": "12"}
    ]

i tried the following but im not able to understand.

let helper = {};
const data = newArr.reduce((acc, currElem) => {
    currElem.elem.forEach(item => {
        if(!helper[currElem.type]) {
            helper[currElem.type] = Object.assign({}, currElem);
            acc.push(helper[currElem.type])
        }else{
            helper[currElem.type].price  = currElem.price;
        helper[currElem.type].discount  = currElem.discount;
        }
    })
    return acc;
}, [])

CodePudding user response:

The following code snippet should do the trick.

As for the explanation:

  1. You want to get a list of all your type objects. You can do this by using flatMap.
  2. Get all the unique values for type. In ES6 you can use SET to get all unqiue values in a list
  3. Then you can use filter to get all objects with the same type and subsequently use reduce on only those.

Note: Since count doesn't exist you need to define an initial value for it and since you define count you also have to define the other values you perform a reduce operation on. (No need for id since there since you assign it direclty and the previous value doesn't matter)

I hope you can follow my short explanation.

const newJson = {
        "w_elem": [
            {
                "elem": [
                    {"type": "type_a","price": "100","discount": "10"},
                    {"type": "type_b","price": "120","discount": "12"},
                    {"type": "type_a","price": "165","discount": "10"}
                ],
                "user": "1001",
                "userType": "A"
            },
            {
                "elem": [
                    {"type": "type_a","price": "96.2","discount": "5"},
                    {"type": "type_b","price": "15","discount": "0"}
                ],
                "user": "1011",
                "userType": "B"
            },
            {
                "elem": [
                    {"type": "type_a","price": "96.2","discount": "5"},
                    {"type": "type_b","price": "15","discount": "0"}
                ],
                "user": "1011",
                "userType": "B"
            }
        ]
    }
    
const newArr = newJson["w_elem"]   

/* Get all elem */
const flatElem = newArr.flatMap((item) => {
    return item["elem"]
})

const keys = [... new Set(flatElem.map(item => { return item["type"]}))]


let data = keys.map( id => {
   return flatElem.filter( obj => obj["type"] === id )
    .reduce((acc, cur) => (
        {
        type: id,
        count: acc.count   1,
        price: acc.price   parseFloat(cur.price), 
        discount: acc.discount   parseFloat(cur.discount)
      }
    ), {count: 0, price: 0, discount: 0})
})

console.log(data)

CodePudding user response:

You can simplify task by making a flat array of elements. And then group summary values by type.

const data = {"w_elem":[{"elem":[{"type":"type_a","price":"100","discount":"10"},{"type":"type_b","price":"120","discount":"12"},{"type":"type_a","price":"165","discount":"10"}],"user":"1001","userType":"A"},{"elem":[{"type":"type_a","price":"96.2","discount":"5"},{"type":"type_b","price":"15","discount":"0"}],"user":"1011","userType":"B"},{"elem":[{"type":"type_a","price":"96.2","discount":"5"},{"type":"type_b","price":"15","discount":"0"}],"user":"1011","userType":"B"}]};

const elems = data.w_elem.flatMap(({ elem }) => elem);
const result = Object.values(elems.reduce((acc, { type, price, discount }) => {
    acc[type] ??= { type, count: 0, price: 0, discount: 0 };
    acc[type].count  = 1;
    acc[type].price  = Number(price);
    acc[type].discount  = Number(discount);
    
    return acc;
}, {}));

console.log(result);
.as-console-wrapper{min-height: 100%!important; top: 0}

  • Related