Home > Net >  How to reverse query for a record, returning all of its parent and their parents?
How to reverse query for a record, returning all of its parent and their parents?

Time:02-01

Suppose the following,

create schema if not exists my_schema;

CREATE TABLE IF NOT EXISTS my_schema.category (
    id serial PRIMARY KEY,
    category_name VARCHAR (255) NOT NULL,
    subcategories BIGINT[] DEFAULT ARRAY[]::BIGINT[]
);
INSERT INTO my_schema.category VALUES
    (
        1,
        'Pickup/dropoff',
        '{}'
    ),
    (
        2,
        'Electrician',
        '{}'
    ),
    (
        3,
        'Around the house',
        '{2}'
    ),
    (
        4,
        'Personal',
        '{3}'
    );

I'm trying to create breadcrumbs on the frontend. For instance, if Electrician is the selected category, I'd like to render something like Personal > Around the house > Electrician.

Ideally, I'd like the query to return something like,

{
    "id": 2,
    "breadcrumbs": "Personal.Around the house.Electrician"
}

This way, I could just do breadcrumbs.split('.').map(. . .).

Another result that would work is something like,

{
    "id": 2,
    "category_name": "Electrician"
    "breadcrumbs": [
        {
            "id": 4,
            "category_name": "Personal"
        },
        {
            "id": 3,
            "category_name": "Around the house"
        },
    ]
}

Or even,

{
    "breadcrumbs": [
        {
            "id": 4,
            "category_name": "Personal"
        },
        {
            "id": 3,
            "category_name": "Around the house"
        },
        {
            "id": 2,
            "category_name": "Electrician"
        }
    ]
}

How can I attain such a result?

CodePudding user response:

You can do it using WITH RECURSIVE as follows :

to get any breadcrumbs just put its id on the first select where id = 2

WITH RECURSIVE cte(n, id, selectedCat) AS
(
  SELECT 1, id, id::text
  from category 
  where id = 2
  UNION ALL
  SELECT n 1, e.id, ep.selectedCat
  FROM cte AS ep JOIN category AS e
      ON ep.id = ANY (e.subcategories)
)
SELECT selectedCat, string_agg(category_name, ',') as breadcrumbs FROM (
  SELECT selectedCat, category_name
  FROM cte 
  inner join category c on c.id = cte.id
  order by n desc
) AS s
GROUP BY selectedCat

demo here

  • Related