André R. André R. - 1 month ago 9
Javascript Question

Aggregating multiple object arrays and sum their properties up

I'm looking for the best performing method to solve the following task: Given is some array as the one below, which contains monthly data. I already use the Array.filter() method beforehand, so this example is already reduced to two months. For readability, I have used a JSON beautifier.

var dbSource = [
{
"t":"2016-10-01T00:00:00",
"c":968,
"d":[
{
"eka1":1,
"anz1":22,
"kos1":4400,
"tag1":"1E"
},
{
"eka1":1,
"anz1":1,
"kos1":200,
"tag1":"1K"
},
{
"eka1":1,
"anz1":12,
"kos1":2400,
"tag1":"1N"
},
{
"eka1":1,
"anz1":41,
"kos1":8200,
"tag1":"1R"
},
{
"eka2":0.6364,
"anz2":11,
"kos2":1600,
"tag2":"2A"
},
{
"eka2":1,
"anz2":6,
"kos2":1200,
"tag2":"2D"
},
{
"eka2":1,
"anz2":2,
"kos2":400,
"tag2":"2E"
},
{
"eka2":0.1839,
"anz2":87,
"kos2":6750,
"tag2":"2F"
},
{
"eka2":0.1613,
"anz2":31,
"kos2":2300,
"tag2":"2G"
},
{
"eka2":0.6724,
"anz2":58,
"kos2":8750,
"tag2":"2K"
},
{
"eka2":1,
"anz2":1,
"kos2":200,
"tag2":"2L"
},
{
"eka2":1,
"anz2":3,
"kos2":600,
"tag2":"2Q"
},
{
"eka2":1,
"anz2":181,
"kos2":36200,
"tag2":"2R"
},
{
"eka2":1,
"anz2":1,
"kos2":200,
"tag2":"2S"
},
{
"eka2":1,
"anz2":2,
"kos2":400,
"tag2":"2U"
},
{
"eka2":1,
"anz2":2,
"kos2":400,
"tag2":"2V"
},
{
"eka2":0.0312,
"anz2":64,
"kos2":3500,
"tag2":"2Z"
},
{
"eka4":1,
"anz4":10,
"kos4":2000,
"tag4":"4K"
},
{
"eka4":1,
"anz4":25,
"kos4":5000,
"tag4":"4R"
},
{
"eka4":0.85,
"anz4":40,
"kos4":7100,
"tag4":"4U"
},
{
"eka5":1,
"anz5":16,
"kos5":3200,
"tag5":"5A"
},
{
"eka5":0.875,
"anz5":8,
"kos5":1450,
"tag5":"5B"
},
{
"eka5":1,
"anz5":1,
"kos5":200,
"tag5":"5C"
},
{
"eka5":0.3333,
"anz5":3,
"kos5":300,
"tag5":"5D"
},
{
"eka5":0,
"anz5":1,
"kos5":50,
"tag5":"5F"
},
{
"eka5":0.5,
"anz5":6,
"kos5":750,
"tag5":"5G"
},
{
"eka5":1,
"anz5":33,
"kos5":6600,
"tag5":"5K"
},
{
"eka5":0.5,
"anz5":2,
"kos5":250,
"tag5":"5R"
},
{
"eka5":0.5,
"anz5":4,
"kos5":500,
"tag5":"5S"
},
{
"eka5":0.5,
"anz5":8,
"kos5":1000,
"tag5":"5W"
},
{
"eka6":1,
"anz6":5,
"kos6":1000,
"tag6":"6A"
},
{
"eka6":0,
"anz6":1,
"kos6":50,
"tag6":"6B"
},
{
"eka6":1,
"anz6":1,
"kos6":200,
"tag6":"6P"
},
{
"eka6":1,
"anz6":1,
"kos6":200,
"tag6":"6U"
},
{
"eka9":1,
"anz9":4,
"kos9":800,
"tag9":"9 "
},
{
"ekaB":0.8605,
"anzB":43,
"kosB":7700,
"tagB":"BF"
},
{
"ekaG":1,
"anzG":2,
"kosG":400,
"tagG":"GF"
},
{
"ekaG":1,
"anzG":1,
"kosG":200,
"tagG":"GT"
},
{
"ekaG":0,
"anzG":1,
"kosG":50,
"tagG":"GU"
},
{
"ekaM":0.9592,
"anzM":49,
"kosM":9500,
"tagM":"MS"
},
{
"ekaO":0.95,
"anzO":80,
"kosO":15400,
"tagO":"OD"
},
{
"ekaO":1,
"anzO":5,
"kosO":1000,
"tagO":"OE"
},
{
"ekaO":1,
"anzO":7,
"kosO":1400,
"tagO":"OL"
},
{
"ekaO":1,
"anzO":11,
"kosO":2200,
"tagO":"OM"
},
{
"ekaO":1,
"anzO":16,
"kosO":3200,
"tagO":"OP"
},
{
"ekaO":1,
"anzO":46,
"kosO":9200,
"tagO":"OR"
},
{
"ekaO":1,
"anzO":1,
"kosO":200,
"tagO":"OV"
},
{
"ekaT":1,
"anzT":12,
"kosT":2400,
"tagT":"T "
}
]
},
{
"t":"2016-09-01T00:00:00",
"c":1542,
"d":[
{
"eka1":1,
"anz1":25,
"kos1":5000,
"tag1":"1E"
},
{
"eka1":1,
"anz1":4,
"kos1":800,
"tag1":"1F"
},
{
"eka1":1,
"anz1":7,
"kos1":1400,
"tag1":"1K"
},
{
"eka1":1,
"anz1":27,
"kos1":5400,
"tag1":"1N"
},
{
"eka1":1,
"anz1":33,
"kos1":6600,
"tag1":"1R"
},
{
"eka2":0.8095,
"anz2":21,
"kos2":3600,
"tag2":"2A"
},
{
"eka2":1,
"anz2":4,
"kos2":800,
"tag2":"2D"
},
{
"eka2":0.6,
"anz2":5,
"kos2":700,
"tag2":"2E"
},
{
"eka2":0.1333,
"anz2":75,
"kos2":5250,
"tag2":"2F"
},
{
"eka2":0.4302,
"anz2":86,
"kos2":9850,
"tag2":"2G"
},
{
"eka2":0.7703,
"anz2":74,
"kos2":12250,
"tag2":"2K"
},
{
"eka2":1,
"anz2":7,
"kos2":1400,
"tag2":"2L"
},
{
"eka2":1,
"anz2":1,
"kos2":200,
"tag2":"2Q"
},
{
"eka2":1,
"anz2":322,
"kos2":64400,
"tag2":"2R"
},
{
"eka2":1,
"anz2":3,
"kos2":600,
"tag2":"2U"
},
{
"eka2":1,
"anz2":7,
"kos2":1400,
"tag2":"2V"
},
{
"eka2":0.0345,
"anz2":58,
"kos2":3200,
"tag2":"2Z"
},
{
"eka4":1,
"anz4":3,
"kos4":600,
"tag4":"4A"
},
{
"eka4":1,
"anz4":1,
"kos4":200,
"tag4":"4F"
},
{
"eka4":1,
"anz4":1,
"kos4":200,
"tag4":"4H"
},
{
"eka4":1,
"anz4":28,
"kos4":5600,
"tag4":"4K"
},
{
"eka4":1,
"anz4":44,
"kos4":8800,
"tag4":"4R"
},
{
"eka4":0.6667,
"anz4":45,
"kos4":6750,
"tag4":"4U"
},
{
"eka5":1,
"anz5":29,
"kos5":5800,
"tag5":"5A"
},
{
"eka5":1,
"anz5":6,
"kos5":1200,
"tag5":"5B"
},
{
"eka5":0.5,
"anz5":2,
"kos5":250,
"tag5":"5C"
},
{
"eka5":1,
"anz5":2,
"kos5":400,
"tag5":"5D"
},
{
"eka5":0.6667,
"anz5":6,
"kos5":900,
"tag5":"5F"
},
{
"eka5":0.6,
"anz5":10,
"kos5":1400,
"tag5":"5G"
},
{
"eka5":1,
"anz5":61,
"kos5":12200,
"tag5":"5K"
},
{
"eka5":1,
"anz5":1,
"kos5":200,
"tag5":"5R"
},
{
"eka5":0.8571,
"anz5":7,
"kos5":1250,
"tag5":"5S"
},
{
"eka5":1,
"anz5":1,
"kos5":200,
"tag5":"5W"
},
{
"eka6":1,
"anz6":5,
"kos6":1000,
"tag6":"6A"
},
{
"eka6":1,
"anz6":2,
"kos6":400,
"tag6":"6B"
},
{
"eka6":1,
"anz6":1,
"kos6":200,
"tag6":"6P"
},
{
"eka6":1,
"anz6":1,
"kos6":200,
"tag6":"6U"
},
{
"eka9":1,
"anz9":1,
"kos9":200,
"tag9":"9 "
},
{
"ekaB":0.9412,
"anzB":119,
"kosB":22750,
"tagB":"BF"
},
{
"ekaG":1,
"anzG":4,
"kosG":800,
"tagG":"GF"
},
{
"ekaG":1,
"anzG":1,
"kosG":200,
"tagG":"GP"
},
{
"ekaG":0,
"anzG":1,
"kosG":50,
"tagG":"GU"
},
{
"ekaM":0.9891,
"anzM":92,
"kosM":18250,
"tagM":"MS"
},
{
"ekaO":0.9732,
"anzO":112,
"kosO":21950,
"tagO":"OD"
},
{
"ekaO":1,
"anzO":9,
"kosO":1800,
"tagO":"OE"
},
{
"ekaO":1,
"anzO":12,
"kosO":2400,
"tagO":"OL"
},
{
"ekaO":1,
"anzO":22,
"kosO":4400,
"tagO":"OM"
},
{
"ekaO":1,
"anzO":27,
"kosO":5400,
"tagO":"OP"
},
{
"ekaO":1,
"anzO":111,
"kosO":22200,
"tagO":"OR"
},
{
"ekaO":1,
"anzO":5,
"kosO":1000,
"tagO":"OV"
},
{
"ekaT":1,
"anzT":11,
"kosT":2200,
"tagT":"T "
}
]
}
]


The array consists of any number of identical objects with a timestamp t (first day of the month), a total count of entries c, as well as a data array d. The data array always contains four properties, ekaX (percentage), anzX (count), kosX (decimal value) and tagX (string value; group name), while X can be a arbitrary alphanumeric character (which is always identical to the first char of tagX).

For a chart, I need to aggregate these values. This means, that anzX and kosX should be summed up, the resulting ekaX should be a weighted average with anzX as weight, and tagX should remain as group name. Objects with different tagX values mustn't be aggregated. The result should be a single d type object.

I researched for quite some time, but I haven't found a simple way yet. Array.reduce() seems to be an appropriate method, but I don't know, if and how I can use it in such a complex context.

I would be really thankful, if a more advanced JavaScript developer could help me out. My focus is more on vb.net, so I'm pretty new to JavaScript.

Answer

Collect all values and build new objects with a hash table.

var dbSource = [{ t: "2016-10-01T00:00:00", c: 968, d: [{ eka1: 1, anz1: 22, kos1: 4400, tag1: "1E" }, { eka1: 1, anz1: 1, kos1: 200, tag1: "1K" }, { eka1: 1, anz1: 12, kos1: 2400, tag1: "1N" }, { eka1: 1, anz1: 41, kos1: 8200, tag1: "1R" }, { eka2: 0.6364, anz2: 11, kos2: 1600, tag2: "2A" }, { eka2: 1, anz2: 6, kos2: 1200, tag2: "2D" }, { eka2: 1, anz2: 2, kos2: 400, tag2: "2E" }, { eka2: 0.1839, anz2: 87, kos2: 6750, tag2: "2F" }, { eka2: 0.1613, anz2: 31, kos2: 2300, tag2: "2G" }, { eka2: 0.6724, anz2: 58, kos2: 8750, tag2: "2K" }, { eka2: 1, anz2: 1, kos2: 200, tag2: "2L" }, { eka2: 1, anz2: 3, kos2: 600, tag2: "2Q" }, { eka2: 1, anz2: 181, kos2: 36200, tag2: "2R" }, { eka2: 1, anz2: 1, kos2: 200, tag2: "2S" }, { eka2: 1, anz2: 2, kos2: 400, tag2: "2U" }, { eka2: 1, anz2: 2, kos2: 400, tag2: "2V" }, { eka2: 0.0312, anz2: 64, kos2: 3500, tag2: "2Z" }, { eka4: 1, anz4: 10, kos4: 2000, tag4: "4K" }, { eka4: 1, anz4: 25, kos4: 5000, tag4: "4R" }, { eka4: 0.85, anz4: 40, kos4: 7100, tag4: "4U" }, { eka5: 1, anz5: 16, kos5: 3200, tag5: "5A" }, { eka5: 0.875, anz5: 8, kos5: 1450, tag5: "5B" }, { eka5: 1, anz5: 1, kos5: 200, tag5: "5C" }, { eka5: 0.3333, anz5: 3, kos5: 300, tag5: "5D" }, { eka5: 0, anz5: 1, kos5: 50, tag5: "5F" }, { eka5: 0.5, anz5: 6, kos5: 750, tag5: "5G" }, { eka5: 1, anz5: 33, kos5: 6600, tag5: "5K" }, { eka5: 0.5, anz5: 2, kos5: 250, tag5: "5R" }, { eka5: 0.5, anz5: 4, kos5: 500, tag5: "5S" }, { eka5: 0.5, anz5: 8, kos5: 1000, tag5: "5W" }, { eka6: 1, anz6: 5, kos6: 1000, tag6: "6A" }, { eka6: 0, anz6: 1, kos6: 50, tag6: "6B" }, { eka6: 1, anz6: 1, kos6: 200, tag6: "6P" }, { eka6: 1, anz6: 1, kos6: 200, tag6: "6U" }, { eka9: 1, anz9: 4, kos9: 800, tag9: "9 " }, { ekaB: 0.8605, anzB: 43, kosB: 7700, tagB: "BF" }, { ekaG: 1, anzG: 2, kosG: 400, tagG: "GF" }, { ekaG: 1, anzG: 1, kosG: 200, tagG: "GT" }, { ekaG: 0, anzG: 1, kosG: 50, tagG: "GU" }, { ekaM: 0.9592, anzM: 49, kosM: 9500, tagM: "MS" }, { ekaO: 0.95, anzO: 80, kosO: 15400, tagO: "OD" }, { ekaO: 1, anzO: 5, kosO: 1000, tagO: "OE" }, { ekaO: 1, anzO: 7, kosO: 1400, tagO: "OL" }, { ekaO: 1, anzO: 11, kosO: 2200, tagO: "OM" }, { ekaO: 1, anzO: 16, kosO: 3200, tagO: "OP" }, { ekaO: 1, anzO: 46, kosO: 9200, tagO: "OR" }, { ekaO: 1, anzO: 1, kosO: 200, tagO: "OV" }, { ekaT: 1, anzT: 12, kosT: 2400, tagT: "T " }] }, { t: "2016-09-01T00:00:00", c: 1542, d: [{ eka1: 1, anz1: 25, kos1: 5000, tag1: "1E" }, { eka1: 1, anz1: 4, kos1: 800, tag1: "1F" }, { eka1: 1, anz1: 7, kos1: 1400, tag1: "1K" }, { eka1: 1, anz1: 27, kos1: 5400, tag1: "1N" }, { eka1: 1, anz1: 33, kos1: 6600, tag1: "1R" }, { eka2: 0.8095, anz2: 21, kos2: 3600, tag2: "2A" }, { eka2: 1, anz2: 4, kos2: 800, tag2: "2D" }, { eka2: 0.6, anz2: 5, kos2: 700, tag2: "2E" }, { eka2: 0.1333, anz2: 75, kos2: 5250, tag2: "2F" }, { eka2: 0.4302, anz2: 86, kos2: 9850, tag2: "2G" }, { eka2: 0.7703, anz2: 74, kos2: 12250, tag2: "2K" }, { eka2: 1, anz2: 7, kos2: 1400, tag2: "2L" }, { eka2: 1, anz2: 1, kos2: 200, tag2: "2Q" }, { eka2: 1, anz2: 322, kos2: 64400, tag2: "2R" }, { eka2: 1, anz2: 3, kos2: 600, tag2: "2U" }, { eka2: 1, anz2: 7, kos2: 1400, tag2: "2V" }, { eka2: 0.0345, anz2: 58, kos2: 3200, tag2: "2Z" }, { eka4: 1, anz4: 3, kos4: 600, tag4: "4A" }, { eka4: 1, anz4: 1, kos4: 200, tag4: "4F" }, { eka4: 1, anz4: 1, kos4: 200, tag4: "4H" }, { eka4: 1, anz4: 28, kos4: 5600, tag4: "4K" }, { eka4: 1, anz4: 44, kos4: 8800, tag4: "4R" }, { eka4: 0.6667, anz4: 45, kos4: 6750, tag4: "4U" }, { eka5: 1, anz5: 29, kos5: 5800, tag5: "5A" }, { eka5: 1, anz5: 6, kos5: 1200, tag5: "5B" }, { eka5: 0.5, anz5: 2, kos5: 250, tag5: "5C" }, { eka5: 1, anz5: 2, kos5: 400, tag5: "5D" }, { eka5: 0.6667, anz5: 6, kos5: 900, tag5: "5F" }, { eka5: 0.6, anz5: 10, kos5: 1400, tag5: "5G" }, { eka5: 1, anz5: 61, kos5: 12200, tag5: "5K" }, { eka5: 1, anz5: 1, kos5: 200, tag5: "5R" }, { eka5: 0.8571, anz5: 7, kos5: 1250, tag5: "5S" }, { eka5: 1, anz5: 1, kos5: 200, tag5: "5W" }, { eka6: 1, anz6: 5, kos6: 1000, tag6: "6A" }, { eka6: 1, anz6: 2, kos6: 400, tag6: "6B" }, { eka6: 1, anz6: 1, kos6: 200, tag6: "6P" }, { eka6: 1, anz6: 1, kos6: 200, tag6: "6U" }, { eka9: 1, anz9: 1, kos9: 200, tag9: "9 " }, { ekaB: 0.9412, anzB: 119, kosB: 22750, tagB: "BF" }, { ekaG: 1, anzG: 4, kosG: 800, tagG: "GF" }, { ekaG: 1, anzG: 1, kosG: 200, tagG: "GP" }, { ekaG: 0, anzG: 1, kosG: 50, tagG: "GU" }, { ekaM: 0.9891, anzM: 92, kosM: 18250, tagM: "MS" }, { ekaO: 0.9732, anzO: 112, kosO: 21950, tagO: "OD" }, { ekaO: 1, anzO: 9, kosO: 1800, tagO: "OE" }, { ekaO: 1, anzO: 12, kosO: 2400, tagO: "OL" }, { ekaO: 1, anzO: 22, kosO: 4400, tagO: "OM" }, { ekaO: 1, anzO: 27, kosO: 5400, tagO: "OP" }, { ekaO: 1, anzO: 111, kosO: 22200, tagO: "OR" }, { ekaO: 1, anzO: 5, kosO: 1000, tagO: "OV" }, { ekaT: 1, anzT: 11, kosT: 2200, tagT: "T " }] }],
    grouped = Object.create(null),
    result = [];

dbSource.forEach(function (a) {
    a.d.forEach(function (b) {
        var x = Object.keys(b)[0].slice(-1),
            key = b['tag' + x];

        if (!grouped[key]) {
            grouped[key] = {};
            grouped[key]['kos' + x] = 0;
            grouped[key]['anz' + x] = 0;
            grouped[key]['eka' + x] = 0;
            grouped[key]['tag' + x] = key;
            result.push(grouped[key]);
        }
        grouped[key]['eka' + x] = (grouped[key]['eka' + x] * grouped[key]['anz' + x] + b['eka' + x] * b['anz' + x]) / (grouped[key]['anz' + x] + b['anz' + x]);
        grouped[key]['kos' + x] += b['kos' + x];
        grouped[key]['anz' + x] += b['anz' + x];

    });
});

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