Group array of object nesting some of the keys with specific names

I have this array of objects, that I need to modify to make it easier the rendering.

const items = [
  {
    tab: 'Results',
    section: '2017',
    title: 'Full year Results',
    description: 'Something here',
  },
    {
    tab: 'Results',
    section: '2017',
    title: 'Half year Results',
    description: 'Something here',
  },
    {
    tab: 'Reports',
    section: 'Marketing',
    title: 'First Report',
    description: 'Something here',
  },
  ...
];

and I'm trying to modify it, grouping them by specific keys. The idea is to have this output. As you can see the names of the keys could be different than the actual names in the items. I think that makes a bit different from previous posts.

const output = [
  {
    tab: 'Results',
    sections: [
      {
         section: '2017',
         items: [ { 'item that belongs here' }, { ... } ],
      },
  },
  {
    tab: 'Reports',
    sections: [
      {
         section: 'Marketing',
         items: [ { ... }, { ... } ],
      },
  },
...
]

I tried using lodash.groupby, but it doesn't do exactly what i'm looking for. Any idea about how to approach it?

Many thanks!!


This can be done with a clever combinartion of _.map and _.groupBy.

const items = [
  {
    tab: 'Results',
    section: '2017',
    title: 'Full year Results',
    description: 'Something here',
  },
    {
    tab: 'Results',
    section: '2017',
    title: 'Half year Results',
    description: 'Something here',
  },
    {
    tab: 'Reports',
    section: 'Marketing',
    title: 'First Report',
    description: 'Something here',
  }
];

function groupAndMap(items, itemKey, childKey, predic){
    return _.map(_.groupBy(items,itemKey), (obj,key) => ({
        [itemKey]: key,
        [childKey]: (predic && predic(obj)) || obj
    }));
}

var result = groupAndMap(items,"tab","sections", 
                   arr => groupAndMap(arr,"section", "items"));


console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

You could use an object without additional libraries.

The object contains a property _ which keeps the nested arrays of the given nested group.

var items = [{ tab: 'Results', section: '2017', title: 'Full year Results', description: 'Something here' }, { tab: 'Results', section: '2017', title: 'Half year Results', description: 'Something here' }, { tab: 'Reports', section: 'Marketing', title: 'First Report', description: 'Something here' }],
    keys = { tab: 'sections', section: 'items' }, // or more if required
    result = [],
    temp = { _: result };

items.forEach(function (object) {
    Object.keys(keys).reduce(function (level, key) {
        if (!level[object[key]]) {
            level[object[key]] = { _: [] };
            level._.push({ [key]: object[key], [keys[key]]: level[object[key]]._ });
        }
        return level[object[key]];
    }, temp)._.push({ title: object.title, description: object.description });
});

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