Chris Michael
Chris Michael

Reputation: 329

How to apply group by on a property of type array using lodash or pure js

I need to group the data by sub categories, but the property is an array.

I'll appreciate your help, if there is any way to do it with lodash or pure js.

Data Example

const data = [
  { 
     title: "data 1",
     sub_categories:[{ id: 1, name: 'gold'},{ id: 2, name: 'water' }]
  },
  { 
     title: "data 2",
     sub_categories:[{ id: 2, name: 'water'}]
  },
 { 
     title: "data 3",
     sub_categories:[{ id: 1, name: 'gold'},{ id: 3, name: 'fire' }]
  },
 { 
     title: "data 4",
     sub_categories:[] // also can be empty
  }
]

Code Example

 _.chain(data)
  .groupBy(props => ) //need help here
  .map(({values, key}) => {
    return {
      values, 
      key
    }
  })
  .value();

Expected output group by subcategory name (this would be a better solution)

[
  {
    subcategory: "gold",
    list: [{title: "data 1"}, {title: "data: 3"}]
  }
]

Upvotes: 0

Views: 520

Answers (3)

Nina Scholz
Nina Scholz

Reputation: 386883

You could group by nested values.

const
    data = [{ title: "data 1", sub_categories: [{ id: 1, name: 'gold' }, { id: 2, name: 'water' }] }, { title: "data 2", sub_categories: [{ id: 2, name: 'water' }] }, { title: "data 3", sub_categories: [{ id: 1, name: 'gold' }, { id: 3, name: 'fire' }] }, { title: "data 4", sub_categories: [] }],
    result = Object.values(data.reduce((r, { title, sub_categories }) => {
        sub_categories.forEach(({ name: subcategory }) => (r[subcategory] ??= { subcategory, list: []}).list.push({ title }));
        return r;
    }, {}));

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

Upvotes: 1

YJR
YJR

Reputation: 1202

var _ = require('lodash');

const data = [
    { 
       title: "data 1",
       sub_categories:[{ id: 1, name: 'gold'},{ id: 2, name: 'water' }]
    },
    { 
       title: "data 2",
       sub_categories:[{ id: 2, name: 'water'}]
    },
   { 
       title: "data 3",
       sub_categories:[{ id: 1, name: 'gold'},{ id: 3, name: 'fire' }]
    },
   { 
       title: "data 4",
       sub_categories:[] // also can be empty
    }
  ]
  
  g= _.groupBy(data.map(d=>d.sub_categories.map(s=>({"title":d.title, "name":s.name }))).flat(),"name")
  ans=[]
  for (const key in g){
    ans.push({"subcategory":key,"list": g[key].map(v=>({"title":v.title}))})
  }
  console.log(
     ans
  )

You can use above code to get the expected results. groupBy using loadash and other operations done using inbuild functions.

Upvotes: 1

Nick Parsons
Nick Parsons

Reputation: 50974

You could do this in a couple of steps, which you can combine together with _.flow():

  1. Create a new array by flat mapping sub_categories. This way we 'expand' the array to now include a data object for each subcatgory.
  2. Group the flattened/expanded array by the name of the subcategory
  3. Map the grouped object to your desired format with _.map()

const data = [ { title: "data 1", sub_categories:[{ id: 1, name: 'gold'},{ id: 2, name: 'water' }] }, { title: "data 2", sub_categories:[{ id: 2, name: 'water'}] }, { title: "data 3", sub_categories:[{ id: 1, name: 'gold'},{ id: 3, name: 'fire' }] }, { title: "data 4", sub_categories:[] /* also can be empty */} ];

const grp = _.flow(
  arr => _.flatMap(arr, obj => _.map(obj.sub_categories, ({name}) => ({...obj, name}))),
  flattened => _.groupBy(flattened, 'name'),
  grpd => _.map(grpd, (arr, subcategory) => ({subcategory, list: _.map(arr, ({title}) => ({title}))}))
);

console.log(grp(data));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

Upvotes: 1

Related Questions