Когда мы используем JS для запроса данных из (реляционной) базы данных, наиболее распространенным способом получения данных является список объектов.

Часто в этих данных повторяются первые значения, например, это дни, отработанные человеком, или покупки, совершенные клиентом.

В моей работе мне часто приходится конвертировать этот список объектов в иерархический объект, т.е. многоуровневый json или другими словами дерево. После некоторого конкретного преобразования я решил потратить некоторое время на создание универсальнойфункции, в которой глубина дерева зависит от количества переданных ключей. к функции.

Поскольку я не думаю, что я единственный, у кого такая необходимость, я решил поделиться этим кодом со всеми вами.

Для функции generateDictFromListOfObj требуются 3 параметра:
- data:список объектов для преобразования
- список levelsKeys: ключей, которые будут использоваться для построения дерева
-
valuesKeys: список ключей, которые представляют собой ключи значений для использования в оставить узлы

/**
 * This method transform a list of object aka rows of a query in a JSON multilevel tree
 * @param {Array.<Object>} data -  the array of object to convert
 * @param {Array.<String>} levelsKeys - the key to use to buld the tree
 * @param {Array.<String>} valuesKeys - the key to use on the leaves (the last level of the tree)
 * @return {Object} - the object build by the function
 */
function generateDictFromListOfObj_simple(data, levelsKeys, valuesKeys) {
    let retObj = {};
    if (data.length === 0)
        return retObj;

    let d= retObj;
    for (let key of levelsKeys) {
        d[data[0][key]] = {};
        d = d[data[0][key]];
    }
    for (let row of data) {
        let d= retObj;
        let lastLevel_d= {};
        let key = null;
        for (key of levelsKeys) {
            if (!d.hasOwnProperty(row[key])) {
                d[row[key]] = {};
            }
            lastLevel_d = d;
            d = d[row[key]];
        }
        let dummy = {};
        for (let keyValue of valuesKeys) {
            dummy[keyValue] = row[keyValue];
        }
        lastLevel_d[row[key]] = dummy;
    }
    return retObj;
}

/**
 * This method transform a list of object aka rows of a query in a JSON multilevel tree
 * @param {Array.<Object>} data -  the array of object to convert
 * @param levelsKeys {Array.<Object>} - the list of object to use to idenfied the keys of the tree, every object has 3 keys
 * @param levelsKeys.key {String} - the key of the level
 * @param levelsKeys.attributes {Array.<String>} - the list of the attributes of that level
 * @param levelsKeys.nested {String} - the name of the key to use for the nested level
 * @return {Object} - the object build by the function
 */
function generateDictFromListOfObj(data, levelsKeys) {
    let retObj = {};
    if (data.length === 0)
        return retObj;

    let d= retObj;
    let row = data[0];
    for (let keyRow of levelsKeys) {
        d[row[keyRow.key]] = {};
        for (let attr of keyRow.attributes) {
            d[row[keyRow.key]][attr] = row[attr]
        }
        d[row[keyRow.key]][keyRow.nested] = {};
        d = d[row[keyRow.key]][keyRow.nested];
    }
    for (let row of data) {
        let d= retObj;
        let lastLevel_d= {};
        let keyRow = null;
        for (keyRow of levelsKeys) {
            if (!d.hasOwnProperty(row[keyRow.key])) {
                d[row[keyRow.key]] = {};
                for (let attr of keyRow.attributes) {
                    d[row[keyRow.key]][attr] = row[attr]
                }
                d[row[keyRow.key]][keyRow.nested] = {};
            }
            lastLevel_d = d;
            d = d[row[keyRow.key]][keyRow.nested];
        }
        let dummy = {};
        for (let keyValue of keyRow.attributes) {
            dummy[keyValue] = row[keyValue];
        }
        lastLevel_d[row[keyRow.key]] = dummy;
    }
    return retObj;
}

Атрибуты, связывающие уровень, определяются в атрибутах, а имя ключа подуровня определяется в вложенном.

И это пример для проверки функции.

let lavorato = [
    {
        dipendente: 'Paolino Paperino',
        cognome: 'Paperino',
        nome: 'Paolino',
        id_commessa: 1286,
        dataiso: '20230901',
        qta: 8,
        commessa: 'ZZZ-000-PLM-VARIE - 3PV246 -  - GALEOTTI',
        colore: '#0088ff',
        descrizione: '#1286 VARIE - PROVA MAPI ',
        id_dipendente: 5
    },
    {
        dipendente: 'Paperino Paolino',
        cognome: 'Paperino',
        nome: 'Paolino',
        id_commessa: 1286,
        dataiso: '20230902',
        qta: 8,
        commessa: 'ZZZ-000-PLM-VARIE - 3PV246 -  - GALEOTTI',
        colore: '#0088ff',
        descrizione: '#1286 VARIE - PROVA MAPI ',
        id_dipendente: 5
    }
];

let levelsKeys = [
    {key: 'id_dipendente', attributes: ["dipendente", "cognome", "nome"], nested: "commesse"},
    {key: 'id_commessa', attributes: ["colore", "commessa"], nested: "giorni"},
    {key: 'dataiso', attributes: ['qta', 'descrizione']}
];

let chk = generateDictFromListOfObj(lavorato, levelsKeys);
console.log(JSON.stringify(chk, null, 2));

Теперь у меня есть то, что мне нужно, но я буду рад получить предложения по улучшению кода.

Хорошие рабочие друзья.