1

I have a json which has the array called as chargeamountunitLevel. I want to sum-up the chargeAmount by grouping by the chargeAmountUnit.The Input json:

 "chargeamountunitLevel": [
        {
            "chargeAmount": 4,
            "chargeAmountUnit": "per hour",
            "currencyCode": "USD"
        },
        {
            "chargeAmount": 50,
            "chargeAmountUnit": "per hour",
            "currencyCode": "USD"
        },
        {
             "chargeAmount": 25,
             "chargeAmountUnit": "per month",
             "currencyCode": "USD"
        },
        {
             "chargeAmount": 25,
             "chargeAmountUnit": "per month",
             "currencyCode": "USD"
        }

    ]

The result might be as follows:

    "chargeamountunitLevel": [
        {
            "chargeAmount": 54,
            "chargeAmountUnit": "per hour",
            "currencyCode": "USD"
        },
        {
             "chargeAmount": 50,
             "chargeAmountUnit": "per month",
             "currencyCode": "USD"
        }

        ]

Any suggestions?

2 Answers 2

3

You could always make use of the reduce function. Here since we provided an initialValue as a second argument to reduce, the first time the callback will be called, that value will be passed as the result argument. Then for all subsequent calls, result will be the return value of the previous call.

Here we basically check in our initialValue object if the chargeAmountUnit of o already exists as a key. If it doesn't, we create a new object having the same property value of the object o and put it in our initialValue object using the chargeAmountUnit as key. If it does exists however, we retrieve the previously created object using chargeAmountUnit as a key and we simply sum up the concerned values.

Also, you may have noticed that we are pushing the created objects in an array, that's because at the end you want an array as a result, not something like:

{
    'per month': {...},
    'per hour': {...}
}

Here's how to do it:

data.reduce(function (result, o) {
    var unit = o.chargeAmountUnit;
    if (!(unit in result)) {
        result.arr.push(result[unit] = { 
            chargeAmountUnit: unit, 
            chargeAmount: o.chargeAmount, 
            currencyCode: o.currencyCode 
        });
    } else {
        result[unit].chargeAmount += o.chargeAmount;
    }

    return result;
}, { arr: [] }).arr;

EDIT: To group by multiple fields, you can simply create a group by key by concanating the group by field string values.

The following will group on chargeAmountUnit and currencyCode.

data.reduce(function (result, o) {
    //compute group by key
    var key = o.chargeAmountUnit + o.currencyCode;
    if (!(key in result)) {
        result.arr.push(result[key] = { 
            chargeAmountUnit: o.chargeAmountUnit, 
            chargeAmount: o.chargeAmount, 
            currencyCode: o.currencyCode 
        });
    } else {
        result[key].chargeAmount += o.chargeAmount;
    }

    return result;
}, { arr: [] }).arr;
Sign up to request clarification or add additional context in comments.

5 Comments

the method given by you working good but cant understand why i get duplicate values in result
@Prem, Could you give an example?
I have resolved getting the duplicates (i got duplicates on console.log(result), but main thing i cant get it from google is how to modify your code if i want to group by based on both chargeAmountUnit and currencyCode.
Naming the array with group is not need in my case
@Prem, I added an example on how to group by multiple fields.
0

you can use underscore.js

here is the code:

var _ = require('underscore');    // use `npm install underscore`
var util = require('util');       // nodejs default modules

var data = {
  "chargeamountunitLevel": [{
    "chargeAmount": 4,
    "chargeAmountUnit": "per hour",
    "currencyCode": "USD"
  }
  , {
    "chargeAmount": 50,
    "chargeAmountUnit": "per hour",
    "currencyCode": "USD"
  }
  , {
    "chargeAmount": 25,
    "chargeAmountUnit": "per month",
    "currencyCode": "USD"
  }
  , {
    "chargeAmount": 10,
    "chargeAmountUnit": "per month",
    "currencyCode": "USD"
  }
  , {
    "chargeAmount": 1,
    "chargeAmountUnit": "per month",
    "currencyCode": "RMB"
  }
  , {
    "chargeAmount": 25,
    "chargeAmountUnit": "per month",
    "currencyCode": "HKD"
  }]
};

// This should give you an array of objects that
// are grouped by chargeAmountUnit.
var tmp = _.groupBy(data["chargeamountunitLevel"], function(d){ 
  return d["chargeAmountUnit"]; 
});
// Show the temporary result :o)
console.log(tmp);

// Now group the result with currency code
var tmp2 = {};
_.each(tmp, function(t, unit){
  tmp2[unit] = _.groupBy(t, function(d){
    return d["currencyCode"];
  });
});

// show the temp result again
console.log("tmp2: \n" +  util.inspect(tmp2, false, null, true));   // util.inspect() is different in node v0.10.x

var finalResult = [];
_.each(tmp2, function(t, unit){
  _.each(t, function(items, currency){
    var total = 0;
    _.each(items, function(item){
      total += item["chargeAmount"];     // should also * currencyCode?
    });
    finalResult.push({
      "chargeAmountUnit" : unit
      , "chargeAmount" : total
      , "currencyCode" : currency    // Update it yourself :o)
    });
  });
});

console.log(finalResult);

3 Comments

Great. Your code working good. How to group the chargeAmount by chargeAmountUnit and currencycode. Because i need to show the currencycode without hardcoding. (Even the currencycode is uniform across all the values in the array)
@Prem, Please note that even in my answer as it is, it's only grouping on the chargeAmountUnit, but not the currencyCode, however it would be easy the fix it. You would simply have to compute a new key. Instead of beins the chargeAmountUnit only, it would be the concatenation o the chargeAmountUnit and the currencyCode.
I agree what @plalx said. You can make a new "key" by concatenating the chargeAmountUnit and currencyCode (E.g. per month|HKD). But I think it is less elegant and as "troublesome" as using two groupBy()s.

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.