Search code examples
sqlpostgresqljoinknex.jsarray-agg

SQL array agg and joins


In my Postgres database, I have 3 tables. One for users one for comments and one to map the two user_comment_map. Here's how the tables look:

users
| id | name | age |
|----|------|-----|
| 1  | user | 20  |


comments
| id | mood  | subject | content         | created_at               |
|----|-------|---------|-----------------|--------------------------|
| 1  | happy | funny   | here is content | Tue Sep 27 2016 13:44:19 |
| 2  | silly | cool    | more content    | Tue Sep 27 2016 14:44:19 |

user_comment_map
| id | user_id | comment_id |
|----|---------|------------|
| 1  |        1|           1|
| 2  |        1|           2|

I'm trying to write a SQL query that results in the following object:

[{
  id: 1,
  name: "user",
  age: 20,
  comments: [
    {
      id: 1,
      mood: "happy",
      subject: "silly",
      content: "here is content",
      created_at: "Tue Sep 27 2016 13:44:19"
    }, 
    {
      id: 2,
      mood: "silly",
      subject: "cool",
      content: "more content",
      created_at: "Tue Sep 27 2016 14:44:19"
    },
  },
  {...}
]

I tried using joins and array_agg but I can't get the data in that format. Any help would be much appreciated. Note: I'm also using knex to build queries but I don't think that knex can handle stuff like this without resorting to knex.raw


Solution

  • This should do it:

    SELECT
        json_build_object(
            'id',id,
            'name',name,
            'comments',(
                SELECT json_agg(json_build_object(
                    'id', comments.id,
                    'mood', comments.mood,
                    'subject', comments.subject,
                    'content', comments.content,
                    'created_at', comments.created_at
                ))
                FROM user_comment_map JOIN comments ON comment_id=comments.id
                WHERE user_id=users.id
            )
        )
    FROM users
    WHERE id=1;