Вложение PostgreSQL результатов реляционного запроса в виде JSON объектов - PullRequest
0 голосов
/ 02 мая 2020

В моей базе данных 3 таблицы: parent, children и grandchildren. Поскольку parent - children и children - grandchildren связаны многие-ко-многим, есть также 2 реляционные таблицы.

У меня есть запрос, который я хотел бы привести ко всем parent элементы с вложенными children и grandchildren строками (если есть) как JSON объекты:

SELECT
  p.*,
  COALESCE(json_agg(json_build_object(
    'child_id', c.child_id,
    'child_name', c.child_name
    -- * GET ALL grandchildren FOR THIS child HERE!
  )) FILTER (WHERE c.child_id IS NOT NULL), '[]')
  AS children
FROM parent p
LEFT JOIN parent_children pc
ON pc.parent_id = p.parent_id
LEFT JOIN children c
ON c.child_id = pc.child_id
GROUP BY p.parent_id;

Этот запрос, позже в моем коде JS, заканчивается как хороший JSON object:

[
  {
    "parent_id": 1,
    "parent_name": "whatever",
    "children": [
      {
        "child_id": 1,
        "child_name": "le child"
      },
      {
        "child_id": 2,
        "child_name": "le second child"
      }
    ]
  },
  {
    "parent_id": 2,
    "parent_name": "second",
    "children": []
  }
]

Как прокомментировано в моем запросе, я хотел бы добавить все grandchildren строк для каждого children элемента. У меня есть запрос, аналогичный приведенному выше, за исключением того, что используются разные таблицы для извлечения этого отношения:

SELECT
  c.*,
  COALESCE(json_agg(json_build_object(
    'grandchild_id', gc.grandchild_id,
    'grandchild_name', gc.grandchild_name
  )) FILTER (WHERE gc.grandchild_id IS NOT NULL), '[]')
  AS grandchildren
FROM children c
LEFT JOIN children_grandchildren cg
ON cg.child_id = c.child_id
LEFT JOIN grandchildren g
ON g.grandchild_id = gc.grandchild_id
GROUP BY c.child_id;

Я не уверен, возможно ли это, и если да, то как именно вложить мои запросы, чтобы получить результаты, такие как:

[
  {
    "parent_id": 1,
    "parent_column": "whatever",
    "children": [
      {
        "child_id": 1,
        "child_name": "le child",
        "grandchildren": [
          {
            "grandchild_id": 1,
            "grandchild_name": "foo"
          },
          {
            "grandchild_id": 2,
            "grandchild_name": "bar"
          }
        ]
      },
      {
        "child_id": 2,
        "child_name": "le second child",
        "grandchildren": []
      }
    ]
  },
  {
    "parent_id": 2,
    "parent_name": "second",
    "children": []
  }
]

1 Ответ

1 голос
/ 04 мая 2020

Мне удалось решить эту проблему, просто LEFT JOIN используя таблицу grandchildren:

SELECT
  p.*,
  COALESCE(json_agg(json_build_object(
    'child_id', c.child_id,
    'child_name', c.child_name
    -- * GET ALL grandchildren FOR THIS child HERE!
  )) FILTER (WHERE c.child_id IS NOT NULL), '[]')
  AS children
FROM parent p
LEFT JOIN parent_children pc
ON pc.parent_id = p.parent_id
LEFT JOIN children c
ON c.child_id = pc.child_id
LEFT JOIN (
  SELECT
    c.*,
    COALESCE(json_agg(json_build_object(
      'grandchild_id', g.grandchild_id,
      'grandchild_name', g.grandchild_name
    ))
    FILTER (WHERE g.grandchild_id IS NOT NULL), '[]') 
    AS grandchildren
  FROM children c
  LEFT JOIN children_grandchildren cg
  ON c.child_id = cg.child_id
  LEFT JOIN grandchildren g
  ON g.grandchild_id = cg.grandchild_id
  GROUP BY c.child_id
) grandchildren ON grandchildren.child_id = c.child_id
GROUP BY p.parent_id;

Это создает объект JSON с такими отношениями, которые мне нужны:

[
  {
    "parent_id": 1,
    "parent_column": "whatever",
    "children": [
      {
        "child_id": 1,
        "child_name": "le child",
        "grandchildren": [
          {
            "grandchild_id": 1,
            "grandchild_name": "foo"
          },
          {
            "grandchild_id": 2,
            "grandchild_name": "bar"
          }
        ]
      },
      {
        "child_id": 2,
        "child_name": "le second child",
        "grandchildren": []
      }
    ]
  },
  {
    "parent_id": 2,
    "parent_name": "second",
    "children": []
  }
]
...