Search code examples
javascriptarraysreactjslodash

Use lodash groupBy function to categorize objects in an array


i have an array of products that each product has a category object. I need to organize by category and include the category object. GroupBy function include only one parameter.

the array of products

const data = [   
  {id: 1, 'name': 'produto1', category: {id: 1, name: 'shirts', description: 'super roupa'}},
  {id: 2, 'name': 'produto2', category: {id: 1, name: 'shirts', description: 'super roupa'}},
  {id: 3, 'name': 'produto3', category: {id: 2, name: 'jackets', description: 'super jackets'}},
  {id: 4, 'name': 'produto4', category: {id: 2, name: 'jackets', description: 'super jackets'}},    
]

expected result:

[
  {
    category: {id: 1, name: 'clothes', description: 'super roupa'}, 
    products:[{id:1, name: 'produt1'}, {id: 2, name: 'produto1'} ]
  },
  {
    category: {id: 2, name: 'jackets', description: 'super jackets'}, 
    products:[{id:3, name: 'produt3'}, {id: 4, name: 'produto4'} ]
  },
]

Solution

  • Group by the category.id, and then map the each group to an object by taking the category from the 1st item in the group, and omitting category from all products:

    const data = [{"id":1,"name":"produto1","category":{"id":1,"name":"shirts","description":"super roupa"}},{"id":2,"name":"produto2","category":{"id":1,"name":"shirts","description":"super roupa"}},{"id":3,"name":"produto3","category":{"id":2,"name":"jackets","description":"super jackets"}},{"id":4,"name":"produto4","category":{"id":2,"name":"jackets","description":"super jackets"}}]
    
    const result = _(data)
      .groupBy('category.id')
      .map(group => ({
        category: _.head(group).category,
        products: _.map(group, o => _.omit(o, 'category'))
      }))
      .value()
    
    console.log(result)
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

    Or the _.flow() function equivalent with lodash/fp:

    const { flow, groupBy, map, head, omit } = _
    
    const fn = flow(
      groupBy('category.id'),
      map(group => ({
        category: head(group).category,
        products: map(omit('category'), group)
      }))
    )
    
    const data = [{"id":1,"name":"produto1","category":{"id":1,"name":"shirts","description":"super roupa"}},{"id":2,"name":"produto2","category":{"id":1,"name":"shirts","description":"super roupa"}},{"id":3,"name":"produto3","category":{"id":2,"name":"jackets","description":"super jackets"}},{"id":4,"name":"produto4","category":{"id":2,"name":"jackets","description":"super jackets"}}]
    
    const result = fn(data)
    
    console.log(result)
    <script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>