How do I return a jsonb array and array of objects from my data?

北战南征 提交于 2019-11-28 10:08:23

问题


I have the following table:

CREATE TABLE mytable (
  id       serial PRIMARY KEY
, employee text UNIQUE NOT NULL
, data     jsonb
);

With the following data:

INSERT INTO mytable (employee, data)
VALUES
 ('Jim', '{"sales_tv": [{"value": 10, "yr": "2010", "loc": "us"}, {"value": 5, "yr": "2011", "loc": "europe"}, {"value": 40, "yr": "2012", "loc": "asia"}], "sales_radio": [{"value": 11, "yr": "2010", "loc": "us"}, {"value": 8, "yr": "2011", "loc": "china"}, {"value": 76, "yr": "2012", "loc": "us"}], "another_key": "another value"}'),
 ('Rob', '{"sales_radio": [{"value": 7, "yr": "2014", "loc": "japan"}, {"value": 3, "yr": "2009", "loc": "us"}, {"value": 37, "yr": "2011", "loc": "us"}], "sales_tv": [{"value": 4, "yr": "2010", "loc": "us"}, {"value": 18, "yr": "2011", "loc": "europe"}, {"value": 28, "yr": "2012", "loc": "asia"}], "another_key": "another value"}')

Notice that there are other keys in there besides just "sales_tv" and "sales_radio". For the queries below I just need to focus on "sales_tv" and "sales_radio".

I need to find all sales for Jim for 2012. Anything that starts with "sales_" and then put that in an object (just need the what the product sold is and the value). e.g.:

    employee   | sales_
    Jim        | {"sales_tv": 40, "sales_radio": 76}

I've got:

SELECT * FROM mytable,
  (SELECT l.key, l.value FROM mytable, lateral jsonb_each_text(data) AS l
    WHERE key LIKE 'sales_%') AS a,
  jsonb_to_recordset(a.value::jsonb) AS d(yr text, value float)
  WHERE mytable.employee = 'Jim'
  AND d.yr = '2012'

But I can't seem to even get just Jim's data. Instead I get:

employee | key         |  value
-------- |------       | -----
Jim      | sales_tv    |  [{"yr": "2010", "loc": "us", "value": 4}, {"yr": "2011", "loc": "europe", "value": 18}, {"yr": "2012", "loc": "asia", "value": 28}]
Jim      | sales_tv    |  [{"yr": "2010", "loc": "us", "value": 10}, {"yr": "2011", "loc": "europe", "value": 5}, {"yr": "2012", "loc": "asia", "value": 40}]
Jim      | sales_radio |  [{"yr": "2010", "loc": "us", "value": 11}, {"yr": "2011", "loc": "china", "value": 8}, {"yr": "2012", "loc": "us", "value": 76}]

回答1:


You treat the result of the first join as JSON, not as text string, so use jsonb_each() instead of jsonb_each_text():

SELECT t.employee, json_object_agg(a.k, d.value) AS sales
FROM   mytable t
JOIN   LATERAL jsonb_each(t.data) a(k,v) ON a.k LIKE 'sales_%'
JOIN   LATERAL jsonb_to_recordset(a.v) d(yr text, value float) ON d.yr = '2012'
WHERE  t.employee = 'Jim'  -- works because employee is unique
GROUP  BY 1;

GROUP BY 1 is shorthand for GROUP BY t.employee.
Result:

employee | sales
---------+--------
Jim      | '{ "sales_tv" : 40, "sales_radio" : 76 }'

I also untangled and simplified your query.

json_object_agg() is instrumental in aggregating name/value pairs as JSON object. Optionally cast to jsonb if you need that - or use jsonb_object_agg() in Postgres 9.5 or later.

Using explicit JOIN syntax to attach conditions in their most obvious place.
The same without explicit JOIN syntax:

SELECT t.employee, json_object_agg(a.k, d.value) AS sales
FROM   mytable t
     , jsonb_each(t.data)      a(k,v) 
     , jsonb_to_recordset(a.v) d(yr text, value float)
WHERE  t.employee = 'Jim'
AND    a.k LIKE 'sales_%'
AND    d.yr = '2012'
GROUP  BY 1;



回答2:


Your first query can be solved like this (shooting from the hip, no access to PG 9.4 here):

SELECT employee, json_object_agg(key, sales)::jsonb AS sales_
FROM (
  SELECT t.employee, j.key, sum((e->>'value')::int) AS sales
  FROM mytable t,
       jsonb_each(t.data) j,
       jsonb_array_elements(j.value) e
  WHERE t.employee = 'Jim'
    AND j.key like 'sales_%'
    AND e->>'yr' = '2012'
  GROUP BY t.employee, j.key) sub
GROUP BY employee;

The trick here is that you use LATERAL joins to "peel away" outer layers of the jsonb object to get at data deeper down. This query is assuming that Jim may have sales in multiple locations.

(Working on your query 2)



来源:https://stackoverflow.com/questions/31549705/how-do-i-return-a-jsonb-array-and-array-of-objects-from-my-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!