Reputation: 345
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'} ]
},
]
Upvotes: 1
Views: 4115
Reputation: 35259
Here's a solution without lodash:
You could reduce
the data array. Destructure the parameter to get category
and rest
of the properties separately. Here rest
will have id
and name
properties. Then create an accumulator object with each unique category's id
as key. Set the value to be the final objects needed in the output. If the key already exists, update it's products
array. Else, add a new key to the accumulator. Then finally use Object.values()
to convert this accumulator object to an array of required values
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 merged = data.reduce((acc, { category, ...rest }) => {
acc[category.id] = acc[category.id] || { category, products: [] };
acc[category.id].products.push(rest);
return acc;
}, {})
console.log(Object.values(merged))
Upvotes: 2
Reputation: 193358
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>
Upvotes: 2