Сокращение объектов до объектов и массивов, когда запрос Express возвращает несколько объектов в запросе многие ко многим - PullRequest
0 голосов
/ 03 марта 2020

У меня есть несколько SQL запросов, которые я выполняю, возвращает несколько объектов, когда в express есть отображение многих на многие, я пытаюсь найти инструмент, позволяющий уменьшить количество общих объектов, чтобы иметь вложенные массивы объектов. ie.

SELECT *
FROM User
LEFT JOIN UserAddress ON UserAddress.user_id = User.user_id
LEFT JOIN Address ON Address.address_id = UserAddress.address_id;

мы получаем ответ

[
  {
    "user_id": 1,
    "name": "test name",
    "address_id": 1,
    "address": "1234 address way"
  },
  {
    "user_id": 1,
    "name": "test name",
    "address_id": 2,
    "address": "5678 new address"
  },
  {
    "user_id": 2,
    "name": "diff name",
    "address_id": 1,
    "address": "1234 address way"
  }
]

, и я хотел бы использовать инструмент в javascript, который уменьшит массив объектов, чтобы он выглядел следующим образом

[
  {
    "user_id": 1,
    "name": "test name",
    "address": [
      {
        "address_id": 1,
        "address": "1234 address way"
      },
      {
        "address_id": 2,
        "address": "5678 new address"
      }
    ]
  },
  {
    "user_id": 2,
    "name": "diff name",
    "address_id": 1,
    "address": "1234 address way"
  }
]

но я не уверен, как это называется или существует какой-либо инструмент, способный это сделать?

1 Ответ

1 голос
/ 03 марта 2020

Вот решение, которое немного обобщенно c, позволяющее вам указать, что вы пытаетесь сопоставить и во что. Он использует объект Map, чтобы помочь с сопоставлением целевого ключа (user_id в вашем случае):

function collate(sourceArray, keyName, collectionName, collectionFields) {
    let collection = new Map();
    for (let item of sourceArray) {
        let targetObj = collection.get(item[keyName]);
        if (!targetObj) {
            targetObj = Object.assign({}, item);
            // remove the properties we are collecting
            for (let field of collectionFields) {
                delete targetObj[field];
            }
            targetObj[collectionName] = [];
            collection.set(item[keyName], targetObj);
        }
        let collectedObj = {};
        // copy over the fields we are collecting
        for (let field of collectionFields) {
            collectedObj[field] = item[field];
        }
        targetObj[collectionName].push(collectedObj);
    }
    // now convert Map to the final array
    return Array.from(collection.values());
}

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

И вы можете использовать его в своих данных следующим образом:

let data = [
  {
    "user_id": 1,
    "name": "test name",
    "address_id": 1,
    "address": "1234 address way"
  },
  {
    "user_id": 1,
    "name": "test name",
    "address_id": 2,
    "address": "5678 new address"
  },
  {
    "user_id": 2,
    "name": "diff name",
    "address_id": 1,
    "address": "1234 address way"
  }
];

function collate(sourceArray, keyName, collectionName, collectionFields) {
    let collection = new Map();
    for (let item of sourceArray) {
        let targetObj = collection.get(item[keyName]);
        if (!targetObj) {
            targetObj = Object.assign({}, item);
            // remove the properties we are collecting
            for (let field of collectionFields) {
                delete targetObj[field];
            }
            targetObj[collectionName] = [];
            collection.set(item[keyName], targetObj);
        }
        let collectedObj = {};
        // copy over the fields we are collecting
        for (let field of collectionFields) {
            collectedObj[field] = item[field];
        }
        targetObj[collectionName].push(collectedObj);
    }
    // now convert Map to the final array
    return Array.from(collection.values());
}

let result = collate(data, "user_id", "address", ["address", "address_id"]);
console.log(result);

Или, если вы действительно не хотите массив из одного элемента, вы можете опубликовать этот процесс в конце:

let data = [
  {
    "user_id": 1,
    "name": "test name",
    "address_id": 1,
    "address": "1234 address way"
  },
  {
    "user_id": 1,
    "name": "test name",
    "address_id": 2,
    "address": "5678 new address"
  },
  {
    "user_id": 2,
    "name": "diff name",
    "address_id": 1,
    "address": "1234 address way"
  }
];

function collate(sourceArray, keyName, collectionName, collectionFields) {
    let collection = new Map();
    for (let item of sourceArray) {
        let targetObj = collection.get(item[keyName]);
        if (!targetObj) {
            targetObj = Object.assign({}, item);
            // remove the properties we are collecting
            for (let field of collectionFields) {
                delete targetObj[field];
            }
            targetObj[collectionName] = [];
            collection.set(item[keyName], targetObj);
        }
        let collectedObj = {};
        // copy over the fields we are collecting
        for (let field of collectionFields) {
            collectedObj[field] = item[field];
        }
        targetObj[collectionName].push(collectedObj);
    }
    // now convert Map to the final array
    let result = Array.from(collection.values());

    // remove single element arrays and copy back to main object
    for (let item of result) {
        let array = item[collectionName];
        if (array.length === 1) {
            // remove the array
            delete item[collectionName];
            // copy the fields from the one array element back to the main object
            Object.assign(item, array[0]);
        }
    }
    return result;
}

let result = collate(data, "user_id", "address", ["address", "address_id"]);
console.log(result);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...