Postgres возвращает json с двумя уровнями вложенности из запроса или функции

Вопрос или проблема

У меня есть три таблицы:

таблица курсов

id название_курса количество_глав
1 курс 1 5
2 курс 2 3

таблица глав

id название_главы количество_подглав course_id –ссылки для courses(id)
1 глава 1 2 1
2 глава 2 4 1
3 глава 3 1 1
4 глава 4 3 1
5 глава 5 0 1
6 глава 1 4 2
7 глава 2 5 2
8 глава 3 0 2

таблица подглав

id название_подглавы chapter_id –ссылки для chapters(id)
1 подглава 1 1
2 подглава 2 1
3 подглава 1 2
4 подглава 2 2
5 подглава 3 2
6 подглава 4 2
7 подглава 1 3
………….

Я хочу, чтобы результат был в формате JSON, как этот:
Я пробовал несколько запросов без успеха

{
  "курс": [
    {
      "course_id": 1,
      "название_курса": "курс 1",
      "количество_глав": 5,
      "главы": [
        {
          "chapter_id": 1,
          "chapter_title": "глава 1",
          "подглавы": [
            {
              "sub_chapter_id": 1,
              "название_подглавы": "подглава 1"
            },
            {
              "sub_chapter_id": 2,
              "название_подглавы": "подглава 2"
            },
            {
              "sub_chapter_id": 3,
              "название_подглавы": "подглава 3"
            }
          ]
        },
        {
          "chapter_id": 2,
          "chapter_title": "глава 2",
          "подглавы": [
            {
              "sub_chapter_id": 1,
              "название_подглавы": "подглава 1"
            },
            {
              "sub_chapter_id": 2,
              "название_подглавы": "подглава 2"
            }
          ]
        }
      ]
    }
  ]
}

Ответ или решение

Для получения данных из базы данных PostgreSQL в формате JSON с двумя уровнями вложенности, как в вашем примере, мы можем использовать оператор json_agg() и json_build_object(). Данный подход позволит вам объединить данные из трёх связанных таблиц: courses, chapters и sub_chapters.

Шаг 1: Описание связи между таблицами

Перед тем как перейти к написанию запроса, давайте кратко рассмотрим структуру и связи между таблицами:

  1. Таблица courses содержит информацию о курсах.
  2. Таблица chapters содержит главы, которые относятся к конкретным курсам по полю course_id.
  3. Таблица sub_chapters включает подглавы, которые связаны с главами по полю chapter_id.

Шаг 2: SQL-запрос для получения нужного формата

Ниже представлен SQL-запрос, который создаёт требуемую структуру JSON:

SELECT json_build_object(
    'course', json_agg(
        json_build_object(
            'course_id', c.id,
            'course_title', c.course_title,
            'chapters_count', c.chapters_count,
            'chapters', (
                SELECT json_agg(
                    json_build_object(
                        'chapter_id', ch.id,
                        'chapter_title', ch.chapter_title,
                        'sub_chapters', (
                            SELECT json_agg(
                                json_build_object(
                                    'sub_chapter_id', sc.id,
                                    'sub_chapter_title', sc.sub_chapter_title
                                )
                            )
                            FROM sub_chapters sc
                            WHERE sc.chapter_id = ch.id
                        )
                    )
                )
                FROM chapters ch
                WHERE ch.course_id = c.id
            )
        )
    )
)
FROM courses c;

Объяснение запроса

  1. Основной запрос: Мы выбираем данные из таблицы courses и используем json_build_object() для создания объекта JSON.
  2. Агрегация курсов: Оператор json_agg() собирает все объекты курсов в массив, формируя поле course.
  3. Глава курсов: Вложенный SELECT выбирает главы курсов, суммируя их в массив chapters, используя аналогичный подход с json_build_object() и json_agg().
  4. Подглавы: Унутренний SELECT из таблицы sub_chapters обеспечивает вложение подглав в соответствующие главы.

Итоговый результат

Запрос вернёт JSON-документ в формате, который вы указали:

{
  "course": [
    {
      "course_id": 1,
      "course_title": "course 1",
      "chapters_count": 5,
      "chapters": [
        {
          "chapter_id": 1,
          "chapter_title": "chapter 1",
          "sub_chapters": [
            {
              "sub_chapter_id": 1,
              "sub_chapter_title": "sub chapter 1"
            },
            {
              "sub_chapter_id": 2,
              "sub_chapter_title": "sub chapter 2"
            }
          ]
        },
        {
          "chapter_id": 2,
          "chapter_title": "chapter 2",
          "sub_chapters": [
            {
              "sub_chapter_id": 1,
              "sub_chapter_title": "sub chapter 1"
            }
          ]
        }
      ]
    }
  ]
}

Заключение

Используя оператор JSON в PostgreSQL, вы можете эффективно агрегировать и структурировать данные с множеством уровней вложенности. Данный подход не только улучшает читаемость и управляемость данных, но и значительно сокращает время, необходимое для последующего извлечения и обработки информации на стороне клиента.

Оцените материал
Добавить комментарий

Капча загружается...