Reputation: 11678
In my previous project I had posts and comments as two tables:
post
comment
Now I've got to design replies to comments. The replies is just one level, so users can only reply to comments, not to replies. The tree structure is only 1 level deep. My first idea was to use the same comment table for both comments and replies. I added a new column though:
comment
Replies have parentcommentid set to the parent comment they belong. Parent comments don't have it (null)
Retrieving comments for a given post is simple:
but this time I need another query to find out the comment replies. This has to be done for each comment:
This doesn't seem to be a good solution, is there a way to have a single query which returns the complete list of comments/replies in the correct order? (dictated by the timestamp and the nesting)
Upvotes: 10
Views: 23900
Reputation: 102
I know this reply is years too late, but hopefully it will help others facing this problem now.
I came up with single table and a single query that returns all the results in the correct order that I use on my own site, it's slightly different but the logic could be used to fit this question.
table name : comments
There is a primary key on (id, ordering, ordering_secondary, source), so no duplicate of these four columns combined will insert.
Inserting a comment you first check "ordering" and increment the new comment by 1.
SELECT ordering FROM comments WHERE id="page id" AND source=0 ORDER BY ordering DESC LIMIT 1
"source" column will be "0" for parent, "1" for a reply for example. So just insert the comment with the ordering value incremented by 1 for each comment on a specific id.
When inserting a reply comment, use the same "ordering" value as the parent but increment the "ordering_secondary" column.
SELECT ordering FROM comments WHERE id="page id" AND source=1 AND ordering="parent comment ordering" ORDER BY ordering DESC LIMIT 1
So the data would look like :
In the table there are two parent comments and two replies to the second parent comment. No replies to first parent comment.
This approach is obviously slightly more overhead on inserts as you have to look up the ordering value of the last comment on an "id" but querying the data is simple.
SELECT * FROM comments WHERE id=? ORDER BY ordering DESC, ordering_secondary ASC LIMIT 30
Upvotes: 2
Reputation: 8248
If you're using a database that supports JSON or object aggregation, you can get a nicer result from the query where each top-level comment is a row (and is not duplicated), and the replies are nested in an array/JSON within each row.
This gives you flexibility with what you do with it and also makes it easier to ensure the ordering and nesting is correct.
An example using Postgres:
SELECT
p.id AS post_id,
c.id AS comment_id,
c.message,
JSON_AGG(
JSON_BUILD_OBJECT('comment', r.comment, 'timestamp', r.timestamp)
ORDER BY r.timestamp
) AS child_comments
FROM
post AS p
INNER JOIN comment AS c
ON c.post_id = p.id
LEFT JOIN comment AS r
ON r.parent_id = c.id
WHERE
post.id = <some id>
AND c.parent_id IS NULL
GROUP BY
post.id,
c.id,
c.message
ORDER BY
c.timestamp DESC
;
Note that, as above, this example will only retrieve the top-level and their first-level replies. It won't get replies to replies. You can use recursive commands or additional subqueries to do that.
Upvotes: 1
Reputation: 579
You may use join and achieve result in single query like I provided below:
SELECT *, cc.message as replied_message
FROM `post`
JOIN comment as c
ON c.postid = post.id
JOIN comment as cc
ON cc.id = c.parentcommentid
ORDER BY c.timestamp DESC, cc.timestamp DESC;
Please note that, it works correctly only if 1 comment have 1 reply only.multiple replies on single comment will not support by this query
Upvotes: 4