Вопрос или проблема
У меня есть три таблицы:
таблица курсов
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: Описание связи между таблицами
Перед тем как перейти к написанию запроса, давайте кратко рассмотрим структуру и связи между таблицами:
- Таблица
courses
содержит информацию о курсах. - Таблица
chapters
содержит главы, которые относятся к конкретным курсам по полюcourse_id
. - Таблица
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;
Объяснение запроса
- Основной запрос: Мы выбираем данные из таблицы
courses
и используемjson_build_object()
для создания объекта JSON. - Агрегация курсов: Оператор
json_agg()
собирает все объекты курсов в массив, формируя полеcourse
. - Глава курсов: Вложенный
SELECT
выбирает главы курсов, суммируя их в массивchapters
, используя аналогичный подход сjson_build_object()
иjson_agg()
. - Подглавы: Унутренний
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, вы можете эффективно агрегировать и структурировать данные с множеством уровней вложенности. Данный подход не только улучшает читаемость и управляемость данных, но и значительно сокращает время, необходимое для последующего извлечения и обработки информации на стороне клиента.