Как эффективно сформировать массив для каждой строки из объединения нескольких таблиц в PostgreSQL?

#sql #postgresql #knex.js

#sql #postgresql #knex.js

Вопрос:

У меня есть шесть таблиц, которые мне нужно объединить и вернуть большой фрагмент данных из PostgreSQL и Knex.js , или необработанный запрос, если Knex его не поддерживает. Учетные записи, учащиеся, когорты, типы когорт, навыки, навыки учащихся.

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

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

Навыки: ID PK, умение

Skill_type: идентификатор PK, skill_id FK, тип

Student_Skills: ID PK, Student_ID FK, Skill_ID FK

Для целей этого запроса тип навыка не имеет значения. Мне нужно вернуть имя навыка для каждого навыка ученика, а не идентификатор навыка.

Каждый возвращенный студент может обладать несколькими навыками, и именно здесь я сталкиваюсь со своей проблемой. По сути, мне нужно сформировать массив в каждой строке возвращаемого значения со столбцом Skills, который содержит все навыки для этого идентификатора студента. Пример:

     "id": 1,
    "profile_pic": null,
    "location": "somewhere",
    "relocatable": true,
    "website": "some-site",
    "github": null,
    "linkedin": "linkedin",
    "twitter": "twitter",
    "first_name": "name",
    "last_name": "last",
    "cohort_name": null,
    "track": null,
    "skills": [
      "HTML",
      "CSS",
      "SASS"
    ]
  

Способ, которым я в настоящее время успешно это сделал, — получить всех учащихся без навыков, а затем выполнить индивидуальный запрос для каждого учащегося, чтобы получить и изменить их навыки.

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

В качестве альтернативы, я мог бы получить все навыки учащихся и перебирать каждый из массивов, сопоставляя навыки, которым соответствует идентификатор студента. Я тоже не уверен, что это правильный путь.

Мой текущий рабочий код:

 cards = await db("students")
        .select(
          "students.id",
          "students.profile_pic",
          "students.location",
          "students.relocatable",
          "students.website",
          "students.github",
          "students.linkedin",
          "students.twitter",
          "students.careers_approved",
          "accounts.first_name",
          "accounts.last_name",
          "cohorts.cohort_name",
          "cohort_types.type as track"
        )
        .innerJoin("accounts", "accounts.id", "students.account_id")
        .leftOuterJoin("cohorts", "students.cohort_id", "cohorts.id")
        .leftOuterJoin(
          "cohort_types",
          "cohorts.cohort_type_id",
          "cohort_types.id"
        );

cards = bluebird.map(cards, async card => {
        skills = await db("student_skills")
          .select("skills.skill")
          .innerJoin("skills", "skills.id", "student_skills.skill_id")
          .where({ "student_skills.student_id": card.id });

        return {
          ...card,
          skills: skills.map(skill => skill.skill)
        };
     });
  

Есть ли какие-либо эксперты по SQL, которые могли бы помочь мне правильно справиться с этим?