I have a table A
, where data
is a json column, and timestamp
is a timestamp with timezone column:
timestamp | data |
---|---|
2023-08-29 13:00:00-04 | { "a_123":{ "temp":85, "uv":5, "rain":0 }, "b_123":{ "temp":85, "uv":5, "rain":0 } } |
2023-08-29 14:00:00-04 | { "a_123":{ "temp":70, "uv" 1:, 1"rain":5 }, "b_123":{ "temp":73, "uv":1, "rain":7 } } |
2023-08-29 15:00:00-04 | { "a_123":{ "temp":83, "uv":4, "rain":1 }, "b_123":{ "temp":87, "uv":7, "rain":0 } } |
I have a second table B
:
id | location | elevation | tag |
---|---|---|---|
a_123 | 04662 | 155m | blue |
b_123 | 84003 | 15m | yellow |
I can map individual data column keys eg. a_123
from table A
onto the matching id
from table B
but in my case the data column keys from table A
are dynamic.
How would I produce a table where the nested timestamp data is mapped to each id
as follows, from the sample data provided above? Thanks for any help/docs.
id | location | elevation | tag | data |
---|---|---|---|---|
a_123 | 04662 | 155m | blue | { "2023-08-29 13:00:00-04":{ "temp":85, "uv":5, "rain":0 }, "2023-08-29 14:00:00-04":{ "temp":70, "uv":1, "rain":5 }, "2023-08-29 15:00:00-04":{ "temp":83, "uv":4, "rain":1 } } |
b123 | 84003 | 15m | yellow | { "2023-08-29 13:00:00-04":{ "temp":85, "uv":5, "rain":0 }, "2023-08-29 14:00:00-04":{ "temp":73, "uv":1, "rain":7 }, "2023-08-29 15:00:00-04":{ "temp":87, "uv":7, "rain":0 } } |
2
Answers
fiddle
Extract the object fields from
a.data
withb.id
as key value using the basicjson
operator->
. (This way we don’t process unrelated keys that also might be there.)Build new objects with
a.timestamp
as key and the extracted value from step 1., and aggregate them into a nesting object in one step withjson_object_agg()
.Do all of this in a
LATERAL
join.LEFT JOIN LATERAL ... ON true
, to be precise. See:Aggregating in a lateral subquery keeps you from having to aggregate the outer table
b
as well, which would be unnecessary cost and complication.The operator
?
in the optionalWHERE a.data ? b.id
excludes rows without matching top-level key early. Only works forjsonb
. Uses an index efficiently – if only a small fraction of rows in tableA
matches.You said "json", but I’ll assume the more commonly used
jsonb
. The query works forjson
, too, with the respective functionjson_object_agg()
, and without theWHERE
clause.Using
jsonb_each
with successivecross join
s:See fiddle