Question

I have 2 tables users & groups:

user_id | title         group_id | title  
----------------        ------------------
U_1     | User 1        G_1      | Group 1
U_2     | User 2        G_2      | Group 2
                        G_3      | Group 3

I have a mapping table between users and groups (a many to many relationship):

members

group_id | user_id | user_type
------------------------------
G_1      | U_1     | admin    
G_1      | U_2     | member   
G_2      | U_1     | admin    
G_3      | U_2     | admin    

I'm looking to create a materialized view with nested tables as follows

user_id | title  | groups            
----------------------------------------
U_1     | User 1 | group_id | user_type
        |        |----------------------
        |        | G_1      | admin    
        |        | G_2      | admin    
----------------------------------------
U_2     | User 2 | group_id | user_type
        |        |----------------------
        |        | G_1      | member   
        |        | G_3      | admin    

In my node.js app, I'm basically expecting the following

[
{
    "user_id": "U_1",
    "title": "User 1",
    "groups": [{"group_id": "G_1","user_type": "admin"},{"group_id": "G_2","user_type": "admin"}]
},
{
    "user_id": "U_2",
    "title": "User 2",
    "groups": [{"group_id": "G_1","user_type": "member"},{"group_id": "G_3","user_type": "admin"}]
},
]

This was easy to achieve using MySQL (cast multiset), but I'm having trouble with postgres... Plz help...

Was it helpful?

Solution

There is no such thing as a "nested table" in Postgres, but it seems you just want a JSON representation of the group assignments for each user.

The following query does this:

select u.user_id, 
       u.title,
       jsonb_build_object(
              'user_id', u.user_id, 
              'title', u.title, 
              'groups', jsonb_agg(jsonb_build_object('group_id', g.group_id, 'user_type', m.user_type))) as groups
from members m
  join users u on u.user_id = m.user_id
  join groups g on g.group_id = m.group_id
group by  u.user_id, u.title;

Given your sample data, the above returns:

user_id | title  | groups                                                                                                                                  
--------+--------+-----------------------------------------------------------------------------------------------------------------------------------------
U_1     | User 1 | {"title": "User 1", "groups": [{"group_id": "G_1", "user_type": "admin"}, {"group_id": "G_2", "user_type": "admin"}], "user_id": "U_1"} 
U_2     | User 2 | {"title": "User 2", "groups": [{"group_id": "G_1", "user_type": "member"}, {"group_id": "G_3", "user_type": "admin"}], "user_id": "U_2"}

Online example

Licensed under: CC-BY-SA with attribution
Not affiliated with dba.stackexchange
scroll top