Как переструктурировать массив в javaScript?

Заранее прошу прощения за такой объем строк кода! Помогите, пожалуйста, переструктурировать массив. Сейчас мне приходят данные в виде массива таких объектов (условно, кейсов может быть больше):

let dataToExpandToCheck= [
{ 
codePlatform: 'Platform 1',
codeInstance: 'Instance 1',
codeScheme: 'Scheme 1',
codeTable: 'Table 1",
columns: []
},
{ 
codePlatform: 'Platform 1',
codeInstance: 'Instance 1',
codeScheme: 'Scheme 1',
codeTable: 'Table 2",
columns: []
},
{ 
codePlatform: 'Platform 1',
codeInstance: 'Instance 1',
codeScheme: 'Scheme 2',
codeTable: 'Table 1",
columns: []
},
{ 
codePlatform: 'Platform 1',
codeInstance: 'Instance 2',
codeScheme: 'Scheme 1',
codeTable: 'Table 1",
columns: []
},
{ 
codePlatform: 'Platform 2',
codeInstance: 'Instance 1',
codeScheme: 'Scheme 1',
codeTable: 'Table 1",
columns: []
},
]

Суть задачи в том, что в рамках одной платформы (codePlatform) может быть несколько инстансов (codeInstance), а внутри одного инстанса несколько разных схем (codeScheme), а внутри схем несколько разных таблиц (codeTable). В тех данных, которые я привела: есть 2 платформы (1 и 2). Внутри платформы 1 существует 2 инстанса (1 и 2), внутри инстанса 1 есть схема 1 и схема 2, в схеме 1 лежит 2 таблицы. На платформе 2 один инстанс, одна схема и одна таблица.

Мне необходимо для отправки данных переписать данный массив так, чтобы объект Платформа содержал ее имя и массив с ее инстансами, объект каждого инстанса должен содержать имя инстанса и массив со всеми входящими в него схемами, а объект каждой схемы содержит ее имя и массив с входящими в нее таблицами (объект таблицы, соответственно, включает в себя имя таблицы и массив ее колонок columns). Таким образом в итоге массив должен выглядеть так (повторюсь, в рабочем проекте данных больше и вариантов гораздо больше):

let restrArray = [
{
    codePlatform: 'Platform 1',
    instances: [
        {
            codeInstance: 'Instance 1',
            schemes: [
                {
                    codeScheme: 'Scheme1',
                    tables: [
                        {
                            codeTable: 'Table 1',
                            columns: []
                        },
                        {
                            codeTable: 'Table 2',
                            columns: []
                        }
                    ]
                },
                {
                    codeScheme: 'Scheme 2',
                    tables: [
                        {
                            codeTable: 'Table 1',
                            columns: []
                        }
                    ]
                }
            ]
        },
        {
            codeInstance: 'Instance 2',
            schemes: [
                {
                    codeScheme: 'Scheme1',
                    tables: [
                        {
                            codeTable: 'Table 1',
                            columns: []
                        }
                    ]
                }
            ]
        }
    ]
},
{
    codePlatform: 'Platform 2',
    instances: [
        {
            codeInstance: 'Instance 1',
            schemes: [
                {
                    codeScheme: 'Scheme 1',
                    tables: [
                        {
                            codeTable: 'Table 1',
                            columns: []
                        }
                    ]
                }
            ]
        }
    ]
}

]

Я прописала алгоритм, но он работает некорректно: в некоторых случаях не добавляет инстанс в объект платформы, иногда дублирует таблицы в массиве. Помогите, пожалуйста, понять, как переписать алгоритм:

    const restructureFinalDataToSend  = (
        dataToExpandToCheck,
        setRestructuredDataToSend
    ) => {
        let newDataArray = [];
        let instanceArray = [];
        let instanceObject = {};
        let schemesArray = [];
        let schemeObject = {};
        let tablesArray = [];
        let tableObject = {};
        let platformObject = {};
    for (let i = 0; i < dataToExpandToCheck.length; i++) {
        for (let j = 0; j < i; j++) {
            if (
                dataToExpandToCheck[j].codePlatform ===
                dataToExpandToCheck[i].codePlatform
            ) {
                if (
                    dataToExpandToCheck[j].codeInstance ===
                    dataToExpandToCheck[i].codeInstance
                ) {
                    if (
                        dataToExpandToCheck[j].codeScheme ===
                        dataToExpandToCheck[i].codeScheme
                    ) {
                        tableObject = {
                            codeTable: dataToExpandToCheck[i].codeTable,
                            columns: dataToExpandToCheck[i].columns
                        };
                        tablesArray.push(tableObject);
                        schemeObject = {
                            codeScheme: dataToExpandToCheck[i].codeScheme,
                            tables: tablesArray
                        };
                        schemesArray.push(schemeObject);
                        instanceObject = {
                            codeInstance: dataToExpandToCheck[i].codeInstance,
                            schemes: schemesArray.reduce((o, i) => {
                                if (
                                    !o.find((v) => v.codeScheme == i.codeScheme)
                                ) {
                                    o.push(i);
                                }
                                return o;
                            }, [])
                        };
                        instanceArray.push(instanceObject);
                        platformObject = {
                            codePlatform: dataToExpandToCheck[i].codePlatform,
                            instances: instanceArray.reduce((o, i) => {
                                if (
                                    !o.find(
                                        (v) => v.codeInstance == i.codeInstance
                                    )
                                ) {
                                    o.push(i);
                                }
                                return o;
                            }, [])
                        };
                        newDataArray.push(platformObject);
                    } else {
                        schemeObject = {
                            codeScheme: dataToExpandToCheck[i].codeScheme,
                            tables: [
                                {
                                    codeTable: dataToExpandToCheck[i].codeTable,
                                    columns: dataToExpandToCheck[i].columns
                                }
                            ]
                        };
                        schemesArray.push(schemeObject);
                        instanceObject = {
                            codeInstance: dataToExpandToCheck[i].codeInstance,
                            schemes: schemesArray
                        };
                        instanceArray.push(instanceObject);
                        platformObject = {
                            codePlatform: dataToExpandToCheck[i].codePlatform,
                            instances: instanceArray
                        };
                        newDataArray.push(platformObject);
                    }
                } else {
                    instanceObject = {
                        codeInstance: dataToExpandToCheck[i].codeInstance,
                        schemes: [
                            {
                                codeScheme: dataToExpandToCheck[i].codeScheme,
                                tables: [
                                    {
                                        codeTable:
                                            dataToExpandToCheck[i].codeTable,
                                        columns: dataToExpandToCheck[i].columns
                                    }
                                ]
                            }
                        ]
                    };
                    instanceArray.push(instanceObject);
                    platformObject = {
                        codePlatform: dataToExpandToCheck[i].codePlatform,
                        instances: instanceArray
                    };
                    newDataArray.push(platformObject);
                }
            } else {
                platformObject = {
                    codePlatform: dataToExpandToCheck[i].codePlatform,
                    instances: [
                        {
                            codeInstance: dataToExpandToCheck[i].codeInstance,
                            schemes: [
                                {
                                    codeScheme:
                                        dataToExpandToCheck[i].codeScheme,
                                    tables: [
                                        {
                                            codeTable:
                                                dataToExpandToCheck[i]
                                                    .codeTable,
                                            columns:
                                                dataToExpandToCheck[i].columns
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                };
                newDataArray.push(platformObject);
            }
        }
    }
    let resultArray = newDataArray.reduce((o, i) => {
        if (!o.find((v) => v.codePlatform == i.codePlatform)) {
            o.push(i);
        }
        return o;
    }, []);
    setRestructuredDataToSend(resultArray);
};

Ответы (2 шт):

Автор решения: Miha

Пример где используется временный json для организации данных а затем преобразует его в желаемый формат используя Object.entries()

let dataToExpandToCheck = [
  {
    codePlatform: 'Platform 1',
    codeInstance: 'Instance 1',
    codeScheme: 'Scheme 1',
    codeTable: 'Table 1',
    columns: [],
  },
  {
    codePlatform: 'Platform 1',
    codeInstance: 'Instance 1',
    codeScheme: 'Scheme 1',
    codeTable: 'Table 2',
    columns: [],
  },
  {
    codePlatform: 'Platform 1',
    codeInstance: 'Instance 1',
    codeScheme: 'Scheme 2',
    codeTable: 'Table 1',
    columns: [],
  },
  {
    codePlatform: 'Platform 1',
    codeInstance: 'Instance 2',
    codeScheme: 'Scheme 1',
    codeTable: 'Table 1',
    columns: [],
  },
  {
    codePlatform: 'Platform 2',
    codeInstance: 'Instance 1',
    codeScheme: 'Scheme 1',
    codeTable: 'Table 1',
    columns: [],
  },
];

// platform -> instance -> schema -> table

const tempObject = {};
// 1. Заполняем объект
dataToExpandToCheck.forEach(({ codePlatform, codeInstance, codeScheme, codeTable, columns }) => {
  tempObject[codePlatform] ??= {};
  tempObject[codePlatform][codeInstance] ??= {};
  tempObject[codePlatform][codeInstance][codeScheme] ??= {};
  tempObject[codePlatform][codeInstance][codeScheme][codeTable] = columns;
});

// 2. Преобразуем объект в массив нужной структуры
const restructureFinalDataToSend = Object.entries(tempObject).map(([codePlatform, instances]) => ({
  codePlatform,
  instances: Object.entries(instances).map(([codeInstance, schemes]) => (
    {
      codeInstance,
      schemes: Object.entries(schemes).map(([codeScheme, tables]) => (
        {
          codeScheme,
          tables: Object.entries(tables).map(([codeTable, columns]) => (
            {
              codeTable,
              columns,
            }
          )),
        }
      )),
    }
  )),
}));

console.log(JSON.stringify(restructureFinalDataToSend, null, 2));

→ Ссылка
Автор решения: ksa

Помогите, пожалуйста, переструктурировать массив.

Предложу еще вот такое решение... Все делается в один проход.

console.log(test(data()))
//
function test(arr){
    const def = [
        ['codePlatform', 'instances'],
        ['codeInstance', 'schemes'],
        ['codeScheme', 'tables'],
    ]
    return arr.reduce((res, obj) => (
        def.reduce(gen(res.m, obj), res.a).push({
            codeTable: obj.codeTable, 
            columns: obj.columns
        }),
        res
    ), {a: [], m: new Map}).a
}

//
function gen(m, obj){
    const ak = []
    const fn = ([key, name], trg) => {
        ak.push(obj[key])
        let k = ak.join('.')
        let o
        if (m.has(k)) {
            o = m.get(k)
        } else {
            o = {
                [key]: obj[key],
                [name]: []
            }
            m.set(k, o)
            trg.push(o)
        }
        return o[name]
    }
    return (t, a) => fn(a, t)
}

//
function data(){
    return [
        { 
        codePlatform: 'Platform 1',
        codeInstance: 'Instance 1',
        codeScheme: 'Scheme 1',
        codeTable: 'Table 1',
        columns: []
        },
        { 
        codePlatform: 'Platform 1',
        codeInstance: 'Instance 1',
        codeScheme: 'Scheme 1',
        codeTable: 'Table 2',
        columns: []
        },
        { 
        codePlatform: 'Platform 1',
        codeInstance: 'Instance 1',
        codeScheme: 'Scheme 2',
        codeTable: 'Table 1',
        columns: []
        },
        { 
        codePlatform: 'Platform 1',
        codeInstance: 'Instance 2',
        codeScheme: 'Scheme 1',
        codeTable: 'Table 1',
        columns: []
        },
        { 
        codePlatform: 'Platform 2',
        codeInstance: 'Instance 1',
        codeScheme: 'Scheme 1',
        codeTable: 'Table 1',
        columns: []
        },
    ]
}

→ Ссылка