简体   繁体   中英

Join Postgresql jsonb object with an item from an array in values

I have two tables in my postgresql database which I want to join:

Table 1) platforms:

  ID (INT)  |  data (JSONB)                                        
------------+---------------------------------------------------------
     1      | {"identity": "1", "platformName": "Teradata" }
     2      | {"identity": "2", "platformName": "MSSQL" }

Table 2) users:

  ID (INT)  | data (JSONB)
------------+-----------+---------------
     12     | { "role": "developer", "identity": "12", "accessRights": {"platforms": ["1"]} }
     13     | { "role": "admin", "identity": "13", "accessRights": {"platforms": ["1", "2"]}" }

I need to get the list of platforms along with the list of users who has access to them. Something like this:

  Platform ID | data (JSONB)
------------+-----------+---------------
     1       | [{"role": "developer", "identity": "12"}]
     2       | [{"role": "developer", "identity": "12"}, {"role": "admin", "identity": "13"}]

I thought maybe something like this can help:

SELECT p.id, u.id, u.role
FROM users u
INNER JOIN platforms p ON (u.data->>'accessRights'->'platforms')::text::int = p.id
GROUP BY p.id

But I can't make it work. So is there anyway to get the result I need?

A simple join is not enough because you need to aggregate information from the users.data JSON for each platform.

select p.id as platform_id, u.*
from platforms p
  cross join lateral (
    select jsonb_agg(u.data - 'accessRights') as data
    from users u
    where u.data -> 'accessRights' -> 'platforms' ? p.id::text
  ) as u 

Note this only works because you stored the platform IDs in the array as strings, not as (JSON) integers, because the ? operator only works on strings.

Online example

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM