I have a JSONB
column containing list
of objects
.>
Here’s the table schema:
column Name | Datatype --------------------- timestamp | timestamp data | JSONB
Sample Data
1.
timestamp : 2020-02-02 19:01:21.571429+00
data : [ { "tracker_id": "5", "position": 1 }, { "tracker_id": "11", "position": 2 }, { "tracker_id": "4", "position": 1 } ]
2.
timestamp : 2020-02-02 19:01:23.571429+00
data : [ { "tracker_id": "7", "position": 3 }, { "tracker_id": "4", "position": 2 } ]
3.
timestamp : 2020-02-02 19:02:23.571429+00
data : [ { "tracker_id": "5", "position": 2 }, { "tracker_id": "4", "position": 1 } ]
I need to find the count of the transitions of tracker_id
from position: 1
to position: 2
Here, the output will be 2
, since tracker_id
4
and 5
changed their position
from 1
to 2
.
Note
The transition should be in ascending order depending on the timestamp
The position
change need not to be in the consecutive records.
I’m using timescaledb extension
So far I’ve tried querying the objects in the list od individual record, but I’m not sure how to merge the list objects of each record and query them.
What would be the query for this? Should I write down a stored procedure instead?
Advertisement
Answer
I don’t use timescaledb extension so I would choose pure SQL solution based on unnesting json:
with t (timestamp,data) as (values (timestamp '2020-02-02 19:01:21.571429+00', '[ { "tracker_id": "5", "position": 1 }, { "tracker_id": "11", "position": 2 }, { "tracker_id": "4", "position": 1 } ]'::jsonb), (timestamp '2020-02-02 19:01:23.571429+00', '[ { "tracker_id": "7", "position": 3 }, { "tracker_id": "4", "position": 2 } ] '::jsonb), (timestamp '2020-02-02 19:02:23.571429+00', '[ { "tracker_id": "5", "position": 2 }, { "tracker_id": "4", "position": 1 } ] '::jsonb) ), unnested as ( select t.timestamp, r.tracker_id, r.position from t cross join lateral jsonb_to_recordset(t.data) AS r(tracker_id text, position int) ) select count(*) from unnested u1 join unnested u2 on u1.tracker_id = u2.tracker_id and u1.position = 1 and u2.position = 2 and u1.timestamp < u2.timestamp;