仅访问(和计数)Postgres JSONB 对象数组中的对象值
Access (and count) just object values from Postgres JSONB array of objects
我在 Postgres 数据库中有一个 JSONB 列。我正在存储一个 JSON 对象数组,每个对象都有一个键值对。我确定我可以设计得更好,但现在我坚持这样做。
id | reviews
------------------
1 | [{"apple": "delicious"}, {"kiwi": "not-delicious"}]
2 | [{"orange": "not-delicious"}, {"pair": "not-delicious"}]
3 | [{"grapes": "delicious"}, {"strawberry": "not-delicious"}, {"carrot": "delicious"}]
假设这个 table 叫做 tasks
。虽然每个对象中的键都不是 predictable,但值是。对于每一行,我想知道 reviews
数组中 "delicious" 值的数量和 "not-delicious" 值的数量。
编辑澄清:
我正在寻找上面 table 中每个 id
/行的 delicious/not-delicious 计数。示例所需输出:
id | delicious | not_delicious
-------------------------------
1 | 1 | 1
2 | 0 | 2
3 | 2 | 1
假设 r 是你的 table:
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 作为行标识符,因为我没有其他列并且不需要 long 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)
更新 post
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)
我在 Postgres 数据库中有一个 JSONB 列。我正在存储一个 JSON 对象数组,每个对象都有一个键值对。我确定我可以设计得更好,但现在我坚持这样做。
id | reviews
------------------
1 | [{"apple": "delicious"}, {"kiwi": "not-delicious"}]
2 | [{"orange": "not-delicious"}, {"pair": "not-delicious"}]
3 | [{"grapes": "delicious"}, {"strawberry": "not-delicious"}, {"carrot": "delicious"}]
假设这个 table 叫做 tasks
。虽然每个对象中的键都不是 predictable,但值是。对于每一行,我想知道 reviews
数组中 "delicious" 值的数量和 "not-delicious" 值的数量。
编辑澄清:
我正在寻找上面 table 中每个 id
/行的 delicious/not-delicious 计数。示例所需输出:
id | delicious | not_delicious
-------------------------------
1 | 1 | 1
2 | 0 | 2
3 | 2 | 1
假设 r 是你的 table:
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 作为行标识符,因为我没有其他列并且不需要 long 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)
更新 post
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)