Петлевой ответ на табличный мульти-массив / выравнивание вложенных массивов объектов в линейный массив - PullRequest
1 голос
/ 08 января 2020

Я хочу преобразовать ответ Loopback в табличные / сплющенные множественные массивы (например, ответ от соседнего запроса sql, а не loopback). Пример ввода:

let data = [{
  id: 1,
  type: "sedan",
  vehicles: [{
      id: 1,
      name: 'audi',
      tyres: [{
          id: 1,
          size: "40inch",
          manufacturer: [{
              id: 1,
              name: "General",
              branches: [{
                  id: "1",
                  city: "munich"
                },
                {
                  id: "2",
                  city: "cologne"
                }
              ]
            },
            {
              id: 2,
              name: "Rosana",
              branches: [{
                  id: "3",
                  city: "paris"
                },
                {
                  id: "4",
                  city: "venice"
                }
              ]
            }
          ]
        },
        {
          id: 2,
          size: "60inch",
          manufacturer: [{
            id: 1,
            name: "General",
            branches: [{
                id: "1",
                city: "munich"
              },
              {
                id: "2",
                city: "cologne"
              }
            ]
          }]
        }
      ]
    },
    {
      id: 2,
      name: 'mercedes',
      tyres: [{
        id: 2
        size: "60inch",
        manufacturer: [{
          id: 1,
          name: "General",
          branches: [{
              id: "1",
              city: "munich"
            },
            {
              id: "2",
              city: "cologne"
            }
          ]
        }]
      }]
    }
  ]
}]

Ожидаемый вывод:

expectedOutput = [{
    "id": 1,
    "type": "sedan",
    "vehicles.id.": 1,
    "vehicles.name": "audi",
    "tyres.id": 1,
    "tyres.size": "40inch",
    "manufacturer.id": 1,
    "manufacturer.name": "General",
    "branches.id": 1,
    "branches.city": "munich"
  },
  {
    "id": 1,
    "type": "sedan",
    "vehicles.id.": 1,
    "vehicles.name": "audi",
    "tyres.id": 1,
    "tyres.size": "40inch",
    "manufacturer.id": 1,
    "manufacturer.name": "General",
    "branches.id": 2,
    "branches.city": "cologne"
  },
  {
    "id": 1,
    "type": "sedan",
    "vehicles.id.": 1,
    "vehicles.name": "audi",
    "tyres.id": 1,
    "tyres.size": "40inch",
    "manufacturer.id": 2,
    "manufacturer.name": "Rosana",
    "branches.id": 3,
    "branches.city": "paris"
  },
  {
    "id": 1,
    "type": "sedan",
    "vehicles.id.": 1,
    "vehicles.name": "audi",
    "tyres.id": 1,
    "tyres.size": "40inch",
    "manufacturer.id": 2,
    "manufacturer.name": "Rosana",
    "branches.id": 4,
    "branches.city": "venice"
  },
  {
    "id": 1,
    "type": "sedan",
    "vehicles.id.": 2,
    "vehicles.name": "mercedes",
    "tyres.id": 1,
    "tyres.size": "60inch",
    "manufacturer.id": 1,
    "manufacturer.name": "General",
    "branches.id": 1,
    "branches.city": "munich"
  },
  {
    "id": 1,
    "type": "sedan",
    "vehicles.id.": 2,
    "vehicles.name": "mercedes",
    "tyres.id": 2,
    "tyres.size": "60inch",
    "manufacturer.id": 1,
    "manufacturer.name": "General",
    "branches.id": 2,
    "branches.city": "cologne"
  }
]

Мой код выглядит следующим образом, но каким-то образом он перезаписывает данные при вызове рекурсии или при вызове плоской функции более одного раза (без рекурсии). Функция Flat пытается сгладить 1 строку / уровень при каждом вызове. Возможно, есть лучший рекурсивный подход, который я не смог достичь.

function flat(arr, result) {
  arr.forEach(row => {
    let rows = [];
    keys = Object.keys(row);
    keys.forEach(key => {
      if (Array.isArray(row[key])) {
        rows.push(...merge(rows, row[key], key));
      } else {
        rows.push(row);
      }
    })

    result.push(...rows);
  })
  console.log(result);
// TODO 
   // flat(result, []);
  // each call linerize each level, 
  //should be called untill the whole array is linearized
   //

  return result;
}

function merge(rows, arr, alias) {
  if (!rows.length) {
    rows = [{}]
  }
  let a = arr.map(row => {
    keys = Object.keys(row);
    keys.forEach(key => {
      rows.forEach(r => {
        if (Array.isArray(row[key])) {
          r[key] = row[key];
        } else {
          r[alias + '.' + key] = row[key];
        }
        delete r[alias];
      })
    })
  })

  return a.filter(x=>{
    if(x!== null){
      return x;
    }
  });

1 Ответ

1 голос
/ 09 января 2020

Я переписал функцию, которая выравнивает данные. Вызовите его с объектом данных и пустой строкой как keyPrefix. Он сохраняет полный префикс вместо только последнего родителя (исправляя это должно быть прямо вперед).

function deepCopy(obj) {
    return JSON.parse(JSON.stringify(obj)); // Can be replaced by a better way to deep copy
}

function isPrimitive(test) {
    return (test !== Object(test));
}

function compress(data, keyPrefix) {
    let response = {};

    if (isPrimitive(data)) {
        response[keyPrefix] = data;
    }

    else if (Array.isArray(data)) {
        response = [];
        data.forEach(entry => {
            let compressed = compress(entry, keyPrefix);

            let item = {};

            if (Array.isArray(compressed)) {
                response.push.apply(response, compressed);
            }

            else {
                Object.keys(compressed).forEach(key => {
                    item[key] = compressed[key];
                });

                response.push(item);
            }
        });
    }

    else {
        Object.keys(data).forEach(key => {
            let entry = data[key];

            let compressed = compress(entry, keyPrefix ? keyPrefix + "." + key : key);

            if (Array.isArray(compressed)) {
                if (!Array.isArray(response)) {
                    response = [response];
                }

                let newItems = [];

                response.forEach(already => {
                    compressed.forEach(e => {
                        newItems.push(Object.assign({}, deepCopy(already), e));
                    });
                });

                response = newItems;
            }

            else {
                if (Array.isArray(response)) {
                    response.forEach(item => {
                        item = Object.assign({}, deepCopy(item), compressed);
                    })
                }

                else {
                    response = Object.assign({}, deepCopy(response), compressed);
                }
            }
        });
    }

    return response;
}

Теперь вы можете вызвать эту подпрограмму в своем коде следующим образом:

compress(data, "");

Или, если вы хотите увидеть его вывод:

// Prints the Output Object and uses 2 spaces as indentation
console.log(JSON.stringify(compress(data, ""), null, 2));
...