Dado un objeto anidado arbitrariamente profundo cuya estructura no se conoce hasta el tiempo de ejecución, como
{ "row-0" : { "rec-0" : { "date" : 20220121, "tags" : [ "val-0" ] }, "rec-1" : { "date" : 20220116, "url" : "https://example.com/a", "tags" : [ "val-0", "val-1" ] } }, "row-1" : { "rec-0" : { "date" : 20220116, "url" : "https://example.com/b" } } }Quiero una herramienta / programa para convertirlo reversiblemente en una estructura tabular (2D) como
{ "row-0" : { "['rec-0']['date']" : 20220121, "['rec-0']['tags'][0]" : "val-0", "['rec-1']['date']" : 20220116, "['rec-1']['url']" : "https://example.com/a", "['rec-1']['tags'][0]" : "val-0", "['rec-1']['tags'][1]" : "val-1" }, "row-1" : { "['rec-0']['date']" : 20220116, "['rec-0']['url'']" : "https://example.com/b" } } Este formato dificulta la exportación como CSV y la posterior edición con una aplicación de hoja de cálculo. Las rutas del objeto anidado original están codificadas en las claves (encabezados de columna) como "['rec-0']['date']" y "['rec-0']['tags'][0]" para facilitar la transformación inversa.
¿Cuál es el mejor enfoque para lograr esto?
Puede hacerlo utilizando una función recursiva simple que genera un nombre de clave anidado y un valor final y lo llena en una matriz.
Object.entries es útil en la solución, ya que puede iterar una array o object usando index o key , respectivamente.
const data = { "row-0": { "rec-0": { date: 20220121, tags: ["val-0"], }, "rec-1": { date: 20220116, url: "https://example.com/a", tags: ["val-0", "val-1"], }, }, "row-1": { "rec-0": { date: 20220116, url: "https://example.com/b", }, }, }; const generateNestedKeyNameAndValue = (input, nestedKeyName, keyValueArr) => { if (typeof input === "object") { // array or object - iterate over them const quoteString = Array.isArray(input) ? "" : "'"; Object.entries(input).forEach(([key, value]) => { generateNestedKeyNameAndValue( value, // extend the key name `${nestedKeyName}[${quoteString}${key}${quoteString}]`, keyValueArr ); }); } else { // string or number (end value) keyValueArr.push([nestedKeyName, input]); } }; const output = Object.fromEntries( Object.entries(data).map(([key, value]) => { const generatedKeyValuePairs = []; generateNestedKeyNameAndValue(value, "", generatedKeyValuePairs); return [key, Object.fromEntries(generatedKeyValuePairs)]; }) ); console.log(output);Iterar las entradas actuales usando Array.map() . Genere la ruta de acuerdo con las reglas (consulte la función preparePath ). Para cada valor, verifique si es un objeto (o una matriz). Si es agregar sus llaves a la ruta. De lo contrario, devuelva un objeto { [path]: val } . Aplana todos los objetos extendiéndolos a Object.assing() .
// prepare the key from the current key, isArray(obj), and the previous path const preparePath = (key, obj, path = []) => [ ...path, `[${Array.isArray(obj) ? key : `'${key}'`}]` ] // convert all sub objects to a single object const fn = (obj, path) => Object.assign({}, ...Object.entries(obj) .map(([key, val]) => typeof val === 'object' // if the value is an object ? fn(val, preparePath(key, obj, path)) // iterate it and it to current path : { [preparePath(key, obj, path).join('')]: val } // if the val is not an object, create an object of { [path]: val } )) const data = {"row-0":{"rec-0":{"date":20220121,"tags":["val-0"]},"rec-1":{"date":20220116,"url":"https://example.com/a","tags":["val-0","val-1"]}},"row-1":{"rec-0":{"date":20220116,"url":"https://example.com/b"}}} // iterate the 1st level of the object since and flatten each sub object const result = Object.fromEntries( Object.entries(data).map(([k, v]) => [k, fn(v)]) ) console.log(result)