Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Hi I am trying to merging json objects which has common value.

This is original JSON

{
    "setA":[
        {
            "setId":"setA"
            ,"prodId":"A"
            ,"price":"5"
            ,"delivertCost":"1"
            ,"name":"Set_Prod01"
        }

        ,{
            "setId":"setA"
            ,"prodId":"B"
            ,"price":"5"
            ,"delivertCost":"1"
            ,"name":"Set_Prod01"
        }
    ]
}

Since it has same setId and name, I want to make like below

{
    "setA": {
        "setId":"setA"
        ,"prodId":"A,B"
        ,"price":"5"
        ,"deliveryCost":3
        ,"name":"Set_Prod01"
    }
}

to do this, I made a javascript code like below, but it looks terrible and more the elements has attributes more if else will needed.

function groupBy(coll, f) {
  return coll.reduce(function(acc, x) {
    var k = f(x);
    acc[k] = (acc[k] || []).concat(x);
    return acc;
  }, {});
}

var test = {
  items: [{
    setId: 'setA', prodId: "A", price: '5', deliveryCost : '1', name: "Set_Prod01"
  }, {
    setId: 'setA', prodId: "B", price :'5', deliveryCost : '2', name: "Set_Prod01"
  }]
};

console.log(JSON.stringify(test));

var result = groupBy(test.items, function(x){return x.setId});
//first grouping
console.log(JSON.stringify(result));

//begin spagetti code... T^T
var secondResult = {};
for(var key in result){
    var secondObjForSet = {};
    var setGroup = result[key]; 
    for(var i = 0; i < setGroup.length; i++) {
        var singleSetItem = setGroup[i];
        for(var innerKey in singleSetItem){
            if(innerKey == 'deliveryCost'){
                secondObjForSet[innerKey] = (typeof secondObjForSet[innerKey] == 'undefined') ? 0 + singleSetItem[innerKey] : (secondObjForSet[innerKey] * 1) + (singleSetItem[innerKey] * 1);
            }else if(innerKey == 'prodId'){
                secondObjForSet[innerKey] = 
                    (typeof secondObjForSet[innerKey] == 'undefined' || secondObjForSet[innerKey] == '') ? 
                        singleSetItem[innerKey] : secondObjForSet[innerKey] + ',' + singleSetItem[innerKey];
            }
            else{
                secondObjForSet[innerKey] = singleSetItem[innerKey];
            }
        }
    }
    secondResult[key] = secondObjForSet;
}

console.log(JSON.stringify(secondResult));

not flexible at all. So I need some help to make it more efficiently. Thanks.

share|improve this question
    
Why is deliveryCost 3 and not 2 (1 + 1)? How about price? Why isn't a sum? Not sure I understand what you need... – elclanrs Apr 6 at 14:18
    
Can you explain which fields are merged, which fields are added, which fields remain the same, what's the criteria for merge rather than just throw us some input, output and code? – Joseph the Dreamer Apr 6 at 18:33
    
@elclanrs server send me summed up product price, but they send delivery cost separately. – Juneyoung Oh Apr 7 at 0:48
    
@JosephtheDreamer delivery cost must summed up. and prodId have to connected with comma, and remain others. The code I provided is working, but I think it is totally not efficient. – Juneyoung Oh Apr 7 at 0:50

I am assuming you have the correct target to transform (the input array is filtered).

If you are using es6:

const input = [
    {
        "setId": "setA",
        "prodId": "A",
        "price": 5,
        "deliveryCost": 1,
        "name": "Set_Prod01"
    },
    {
        "setId": "setA",
        "prodId": "B",
        "price": 5,
        "deliveryCost": 2,
        "name": "Set_Prod01"
    }
];

const output = {
    "setId": "setA",
    "prodId": "A,B",
    "price": 5,
    "deliveryCost": 3,
    "name": "Set_Prod01"
};

const groupBy = (input) => (
    Object.assign(
        input[0],
        {
            prodId: input.map(set => set.prodId).join(','),
            deliveryCost: input.map(set => set.deliveryCost).reduce( (cur, next) => cur + next)
        }
    )
);

console.log(output);
console.log(groupBy(input));

If you are using es6 and stage-2 object spread operator, change the function to:

const groupBy = (input) => (
    {
        ...input[0],
        prodId: input.map(set => set.prodId).join(','),
        delivertCost: input.map(set => set.deliveryCost).reduce( (cur, next) => cur + next)
    }
);

If you are not using es6, simplest method is use it, and use babel to convert it into es5 compatible code. It's less code, more readable and easier to maintain.

EDIT: The function above simply take an array of objects and assign them into another object. Note that in Object.assign, the latter's value will overwrite the former's value with the same key, so you can easily implement the overwriting rule you mentioned. The value are simply some functional programming, one join the array of string, and the other sum up the values.

share|improve this answer
    
Welcome to Code Review! You have presented an alternative solution, but haven't reviewed the code. Please explain your reasoning (how your solution works and how it improves upon the original) so that the author can learn from your thought process. – SuperBiasedMan Apr 7 at 11:03
    
Oops i'm sorry, I updated the reason in the answer above. – Kai Hao Apr 7 at 12:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.