Reputation: 33
I have two tables like this
CREATE TABLE posts (
id PRIMARY KEY,
text varchar
);
CREATE TABLE comments (
id PRIMARY KEY,
text varchar,
post_id integer,
reply_to integer -- recursive reference
);
i need query that turns this related data into graph like nested json like this
[
{
text: 'post',
comments: [
{
text: 'normal comment',
replies: [
{ text: 'reply comment' }
]
},
{ text: 'other normal comment' }
]
}
]
so far what i have is this query which gets me comments array but no replies
select row_to_json(t)
from (
select id, text, created_at,
(
select array_to_json(array_agg(row_to_json(d)))
from (
select id, text, post_id, replied_to, created_at
from comments
where post_id = posts.id and replied_to is null
) d
) as comments
from posts
) t
but can't figure out how to query for replies too, so that i have complete tree, pls help
Upvotes: 0
Views: 90
Reputation: 2012
You need to use a recursive query to follow the recursion of the ids.
SELECT row_to_json(t)
FROM (
SELECT id, text,
(
SELECT array_to_json(array_agg(row_to_json(x))) AS comments
FROM (
SELECT id, text, post_id, reply_to,
( SELECT array_to_json(array_agg(row_to_json(d)))
FROM (
WITH RECURSIVE temp
AS
(
SELECT id, text, post_id, reply_to
FROM comments
WHERE reply_to IS NULL
AND post_id = posts.id
AND id = c.id
UNION ALL
SELECT nxt.id, nxt.text, nxt.post_id, nxt.reply_to
FROM temp prv
JOIN comments nxt ON prv.id = nxt.reply_to
WHERE nxt.reply_to IS NOT NULL
) SELECT * FROM temp WHERE reply_to IS NOT NULL
) d
) as replies
FROM comments c
WHERE c.reply_to IS NULL
AND c.post_id = posts.id
) x
)
FROM posts
) t
Here is the SQLFiddle.
Semi-formatted output:
{"id":1,
"text":"Test post",
"comments":[{
"id":1,
"text":"Test comment",
"post_id":1,
"reply_to":null,
"replies":[{
"id":2,
"text":"Test reply",
"post_id":1,
"reply_to":1
},
{"id":3,
"text":"Reply reply",
"post_id":1,
"reply_to":2
}
]},
{"id":4,
"text":"Comment 2",
"post_id":1,
"reply_to":null,
"replies":[{
"id":5,
"text":"Reply 2",
"post_id":1,
"reply_to":4
}]
}
]}
That's a doozy.
If you are able to rename reply_to
to parent_id
it would describe the relationship right in the column name.
Upvotes: 1