Estoy tratando de transformar un archivo JSON que proviene de una API con una estructura similar a esta:
{ "fruitType": {"name": "bananas"}, "plantedIn": {"country": "USA", "state": "Minnesota"}, "harvestMethod": {"name": "manual"}, "product": {"id": "841023781723"}, }, ... (other fruits, or the same fruit planted/harvested differently)En algo como esto:
"bananas": { "USA": { "manual": { "841023781723": { "fruitType": {"name": "bananas"}, "plantedIn": {"country": "USA", "state": "Minnesota"}, "harvestMethod": {"name": "manual"}, "product": {"id": "841023781723"}, } } } }, ... Entonces, esencialmente quiero agrupar primero por fruitType name , luego por plantedIn country , luego por harvestMethod name , y finalmente product id .
Después de investigar un poco, descubrí que lodash es popular para este tipo de agrupación. Desarrollé una solución muy ingenua con sus métodos chain , groupBy y mapValues así:
const _ = require('lodash'); const groupedData = _.chain(data) .groupBy('fruitType.name') .mapValues(values => _.chain(values) .groupBy('plantedIn.country') .mapValues(values => _.chain(values) .groupBy('harvestMethod.name') .mapValues(values => _.chain(values) .groupBy('product.id') .value() ).value() ).value() ).value()Esta solución, aunque funcional, se siente muy detallada y probablemente ineficiente. Por lo tanto, me gustaría preguntar si hay alguna alternativa mejor, ya sea con loadash o de otra manera.
Ya hay una respuesta, pero aquí hay quizás una solución más legible.
const grouped = items.reduce((acumm, current, index) => { acumm[current.fruitType.name] = { [current.plantedIn.country]: { [current.harvestMethod.name]: { [current.product.id]: current, ...(acumm[current.fruitType.name]?. [current.plantedIn.country]?. [current.harvestMethod.name] ?? {} ), }, }, }; return acumm; }, {});Puede tomar una serie de funciones para obtener las claves y construir la estructura.
const data = [{ fruitType: { name: "bananas" }, plantedIn: { country: "USA", state: "Minnesota" }, harvestMethod: { name: "manual" }, product: { id: "841023781723" } }], keys = [o => o.fruitType.name, o => o.plantedIn.country, o => o.harvestMethod.name, o => o.product.id], result = data.reduce((r, o) => { keys.reduce( (q, fn, i, { length }) => q[fn(o)] ??= i + 1 === length ? o : {}, r ); return r; }, {}); console.log(result); .as-console-wrapper { max-height: 100% !important; top: 0; }