I'm trying to run the following query, which unless I'm misunderstanding the documentation looks like it should be possible.
SELECT id, profile
FROM end_user
WHERE profile @? '$.first_segment_exited_at ? (@.datetime() < "2023-05-25".datetime())'::jsonpath;
This is the documentation which leads me to think I should be able to achieve this:
string . datetime() → datetime_type (see note)
Date/time value converted from a string
jsonb_path_query('["2015-8-1", "2015-08-12"]', '$[*] ? (@.datetime() < "2015-08-2".datetime())') → "2015-8-1"
Example profile data, note the dates are valid ISO format;
{
"first_segment_exited_at": "2023-05-22T03:09:37.825Z",
}
The following query returns results, but I'm keen on switching to jsonpath syntax in order to utilize an index
select id, profile
from end_user
where '2023-05-25'::timestamptz > (profile->>'first_segment_exited_at')::timestamptz
I'm running Postgres v14.
Illegal JSON datetime format in the table column. This works:
CREATE TABLE end_user (id int, profile jsonb);
INSERT INTO end_user VALUES
(1, '{"first_segment_exited_at": "2023-05-22T03:09:37.825Z"}')
, (2, '{"first_segment_exited_at": "2023-05-22T03:09:37Z"}') -- no fractional sec
, (3, '{"first_segment_exited_at": "2023-05-22T03:09:37"}') -- no trailing "Z", either
;
SELECT *
FROM end_user
WHERE profile @? '$.first_segment_exited_at ? (@.datetime() < "2023-05-25".datetime())';
Row 3 is the only one with legal format.
(The filter expression needs to be valid, too.)
You didn't get an error message because, quoting the manual:
The
jsonpath
operators@?
and@@
suppress the following errors: missing object field or array element, unexpected JSON item type, datetime and numeric errors. [...] This behavior might be helpful when searching JSON document collections of varying structure.
To debug input strings, test with a function that doesn't suppress the error. Like jsonb_path_query_first()
:
SELECT jsonb_path_query_first('{"d": "2023-05-22T03:09:37.1"}', '$.d.datetime()')
ERROR: datetime format is not recognized: "2023-05-22T03:09:37.1"
HINT: Use a datetime template argument to specify the input data format.
But this one flies:
SELECT jsonb_path_query_first('{"d": "2023-05-22T03:09:37"}', '$.d.datetime()')
Also, you can supply a template pattern to the .datetime()
method like Laurenz demonstrates in his added answer. (More obstacles ahead ...)