如何在postgres中聚合jsonb元素的行?

cro*_*lla 7 sql postgresql jsonb

我想知道是否有任何有效的方法来聚合JSONB列的多行,请考虑以下表结构:

PERFORMANCE(user_id INTEGER, stat_date DATE, metrics JSONB)
Run Code Online (Sandbox Code Playgroud)

像这样的行:

1, 2017-01-01, {"speed":10, "distance":120, "time":5}
1, 2017-01-02, {"speed":15, "distance":150, "time":8}
1, 2017-01-03, {"speed":9, "distance":90}
2, 2017-01-01, {"speed":15, "distance":150, "time":8}
Run Code Online (Sandbox Code Playgroud)

我想通过user_id在SUM中的每个键聚合SUM,因此输出如下所示:

1, {"speed":34, "distance":360, "time":13}
2, {"speed":15, "distance":150, "time":8}
Run Code Online (Sandbox Code Playgroud)

一种选择是使用jsonb_each,但这会爆炸列,我想知道是否有更好的选择.

编辑:重要的是要注意我不知道JSONB列中的每个键,所以我不能显式聚合它们.

谢谢

Oto*_*dze 8

一种方法是从jsonb数据中获取值,使用它们group by user_id然后再次生成jsonb数据:

select user_id, jsonb_build_object('speed', sum((metrics->>'speed')::numeric), 'distance', sum((metrics->>'distance')::numeric) , 'time', sum((metrics->>'time')::numeric) )
from t 
group by user_id
Run Code Online (Sandbox Code Playgroud)

编辑

好吧,在这种情况下,我想如你所说,你可以使用jsonb_each功能(也许有更好的方法,但我现在看不到它).我jsonb_each_text在这里使用,我不知道你的意思but that will explode the column,你可以jsonb_object_agg再次使用"构建"jsonb对象,如下所示:

with your_table(user_id  , stat_date  , metrics) as(
    select 1, '2017-01-01'::date, '{"speed":10, "distance":120, "time":5}'::jsonb union all
    select 1, '2017-01-02'::date, '{"speed":15, "distance":150, "time":8}'::jsonb union all
    select 1, '2017-01-02'::date, '{"bla":8}'::jsonb union all
    select 4, '2017-01-02'::date, '{"bla":8}'::jsonb union all
    select 1, '2017-01-03'::date, '{"speed":9, "distance":90}'::jsonb union all
    select 2, '2017-01-01'::date, '{"speed":15, "distance":150, "time":8}'::jsonb  
)

select user_id, jsonb_object_agg(k, val) from (
    select user_id, k, sum(v::numeric) as val from your_table join lateral  jsonb_each_text(metrics) j(k,v) on true
    group by user_id, k
) tt
group by user_id
Run Code Online (Sandbox Code Playgroud)