Получать доступ (и считать) только к значениям объектов из массива объектов Postgres JSONB - PullRequest
0 голосов
/ 17 мая 2018

У меня есть столбец JSONB в базе данных Postgres.Я храню массив объектов JSON, каждый из которых имеет одну пару ключ-значение.Я уверен, что мог бы спроектировать это лучше, но сейчас я застрял с этим.

id | reviews
------------------
 1 | [{"apple": "delicious"}, {"kiwi": "not-delicious"}]
 2 | [{"orange": "not-delicious"}, {"pair": "not-delicious"}]
 3 | [{"grapes": "delicious"}, {"strawberry": "not-delicious"}, {"carrot": "delicious"}]

Предположим, эта таблица называется tasks.Хотя ключи в каждом из этих объектов не являются предсказуемыми, значения являются.Для каждой строки я хотел бы знать количество «вкусных» и количество «не вкусных» значений в массиве reviews.

Редактировать для уточнения:

I 'm подсчитывает количество вкусных / не очень вкусных напитков для каждой строки id / в приведенной выше таблице.Пример желаемого выхода:

id | delicious | not_delicious
-------------------------------
 1 |         1 |             1
 2 |         0 |             2
 3 |         2 |             1

1 Ответ

0 голосов
/ 17 мая 2018

скажем, r - это ваша таблица:

so=# select * from r;
                                       reviews
-------------------------------------------------------------------------------------
 [{"apple": "delicious"}, {"kiwi": "not-delicious"}]
 [{"orange": "not-delicious"}, {"pair": "not-delicious"}]
 [{"grapes": "delicious"}, {"strawberry": "not-delicious"}, {"carrot": "delicious"}]
(3 rows)

затем:

so=# with j as (select jsonb_array_elements(reviews) a, r, ctid from r)
select jsonb_object_keys(a), a->>jsonb_object_keys(a),ctid from j;
 jsonb_object_keys |   ?column?    | ctid
-------------------+---------------+-------
 apple             | delicious     | (0,1)
 kiwi              | not-delicious | (0,1)
 orange            | not-delicious | (0,2)
 pair              | not-delicious | (0,2)
 grapes            | delicious     | (0,3)
 strawberry        | not-delicious | (0,3)
 carrot            | delicious     | (0,3)
(7 rows)

Я использовал ctid в качестве идентификатора строки, потому что у меня нет другого столбца, и я не хотел долго reviews

и, очевидно, агрегация вкусных в строке:

so=# with j as (select jsonb_array_elements(reviews) a, r, ctid from r)
select ctid, a->>jsonb_object_keys(a), count(*) from j group by a->>jsonb_object_keys(a),ctid;
 ctid  |   ?column?    | count
-------+---------------+-------
 (0,1) | delicious     |     1
 (0,3) | delicious     |     2
 (0,1) | not-delicious |     1
 (0,2) | not-delicious |     2
 (0,3) | not-delicious |     1
(5 rows)

для обновленного сообщения

so=# with j as (select jsonb_array_elements(reviews) a, r, ctid from r)
, n as (
 select ctid,a->>jsonb_object_keys(a) k from j
)
, ag as (
select ctid
, case when k = 'delicious' then 1 else 0 end deli
, case when k = 'not-delicious' then 1 else 0 end notdeli
from n
)
select ctid, sum(deli) deli, sum(notdeli) notdeli from ag group by ctid;
 ctid  | deli | notdeli
-------+------+---------
 (0,1) |    1 |       1
 (0,2) |    0 |       2
 (0,3) |    2 |       1
(3 rows)
...