Steve K Steve K - 5 months ago 13
Javascript Question

Using Lodash, how can I transform this data to the desired format?

I'm fairly new to lodash and suspect that it can help me transform my data in the way I want. I've been reading the lodash docs but to be honest it's not sinking in, I'm not seeing the correct combination of operations I need.

Here is what I want to do:

var configs = [ {
configId: 1,
options: [ {categoryId: 1, id: 100},
{categoryId: 2, id: 200},
{categoryId: 3, id: 300} ] },
{
configId: 2,
options: [ {categoryId: 1, id: 105},
{categoryId: 2, id: 210} ] },
{
configId: 3,
options: [ {categoryId: 2, id: 200},
{categoryId: 1, id: 165},
{categoryId: 3, id: 300} ] }
];

// I want the above to look like this:
/*
[ {categoryId: 1, ids: [100, 105, 165]},
{categoryId: 2, ids: [200, 210]},
{categoryId: 3, ids: [300]} ]
*/


And here is a fiddle if you want to experiment.

When I look at the problem I think I want to:


  1. Combine all the
    configs
    objects so I have one big array of
    options
    objects

  2. Group by
    categoryId

  3. And then I really lose my way... I suspect I could use reduce() here, but then I also think I need a map() to actually produce the transformed object.



Anyway, I'm looping on this and not making progress, I'm hoping someone can point me the right direction.

Answer

With ES2015 Syntax:

_.map(
  _.groupBy(_.flatMap(configs, config => config.options), 'categoryId'), 
  (val, key) => ({categoryId: key, ids: _.uniq(_.map(val, v => v.id)) })
)

ES5 compatible (generated by Babel):

_.map(
  _.groupBy(
    _.flatMap(configs, function (config) {
    return config.options;
    }), 
  'categoryId'), 
  function (val, key) {
    return {
        categoryId: key,
        ids: _.uniq(_.map(val, function (v) {
            return v.id;
        }))
    };
});

Explanation:

_.flatMap(configs, config => config.options)

Takes options array from each configs object, flattens them into a single array of [{categoryId: xx, id: yy}, ...]

_.groupBy(..., 'categoryId')

Groups above array by their categoryId, as [{xx: [categoryId: xx, id: yy}, ...]

_.map(..., (val, key) => ({categoryId: key, ids: _.uniq(_.map(val, v => v.id)) }))

Receives val = [{xx: [categoryId: xx, id: yy}, ...], key: xx and maps them to object where categoryId is set to received key, and ids to array of unique ids from grouped objects. Result is the array you wanted.

Comments