diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index affd1254bb..295f8ca5c9 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -17205,7 +17205,7 @@ array w/o UK? | t For example, suppose you have some JSON data from a GPS tracker that you would like to parse, such as: -{ + \set json '{ "track": { "segments": [ { @@ -17220,7 +17220,7 @@ array w/o UK? | t } ] } -} +}' @@ -17229,7 +17229,10 @@ array w/o UK? | t .key accessor operator to descend through surrounding JSON objects: -$.track.segments +select jsonb_path_query(:'json'::jsonb, '$.track.segments'); + jsonb_path_query +------------------------------------------------------------------------------------------------------------------------------------------------------------------- + [{"HR": 73, "location": [47.763, 13.4034], "start time": "2018-10-14 10:05:14"}, {"HR": 135, "location": [47.706, 13.2635], "start time": "2018-10-14 10:39:21"}] @@ -17239,7 +17242,11 @@ $.track.segments the following path will return the location coordinates for all the available track segments: -$.track.segments[*].location +select jsonb_path_query(:'json'::jsonb, '$.track.segments[*].location'); + jsonb_path_query +------------------- + [47.763, 13.4034] + [47.706, 13.2635] @@ -17248,7 +17255,10 @@ $.track.segments[*].location specify the corresponding subscript in the [] accessor operator. Recall that JSON array indexes are 0-relative: -$.track.segments[0].location +select jsonb_path_query(:'json'::jsonb, 'strict $.track.segments[0].location'); + jsonb_path_query +------------------- + [47.763, 13.4034] @@ -17259,7 +17269,10 @@ $.track.segments[0].location Each method name must be preceded by a dot. For example, you can get the size of an array: -$.track.segments.size() +select jsonb_path_query(:'json'::jsonb, 'strict $.track.segments.size()'); + jsonb_path_query +------------------ + 2 More examples of using jsonpath operators and methods within path expressions appear below in @@ -17302,7 +17315,10 @@ $.track.segments.size() For example, suppose you would like to retrieve all heart rate values higher than 130. You can achieve this using the following expression: -$.track.segments[*].HR ? (@ > 130) +select jsonb_path_query(:'json'::jsonb, '$.track.segments[*].HR ? (@ > 130)'); + jsonb_path_query +------------------ + 135 @@ -17312,7 +17328,10 @@ $.track.segments[*].HR ? (@ > 130) filter expression is applied to the previous step, and the path used in the condition is different: -$.track.segments[*] ? (@.HR > 130)."start time" + select jsonb_path_query(:'json'::jsonb, '$.track.segments[*] ? (@.HR > 130)."start time"'); + jsonb_path_query +----------------------- + "2018-10-14 10:39:21" @@ -17321,7 +17340,10 @@ $.track.segments[*] ? (@.HR > 130)."start time" example, the following expression selects start times of all segments that contain locations with relevant coordinates and high heart rate values: -$.track.segments[*] ? (@.location[1] < 13.4) ? (@.HR > 130)."start time" +select jsonb_path_query(:'json'::jsonb, '$.track.segments[*] ? (@.location[1] < 13.4) ? (@.HR > 130)."start time"'); + jsonb_path_query +----------------------- + "2018-10-14 10:39:21" @@ -17330,46 +17352,81 @@ $.track.segments[*] ? (@.location[1] < 13.4) ? (@.HR > 130)."start time" The following example first filters all segments by location, and then returns high heart rate values for these segments, if available: -$.track.segments[*] ? (@.location[1] < 13.4).HR ? (@ > 130) +select jsonb_path_query(:'json'::jsonb, $.track.segments[*] ? (@.location[1] < 13.4).HR ? (@ > 130)'); + jsonb_path_query +------------------ + 135 You can also nest filter expressions within each other: -$.track ? (exists(@.segments[*] ? (@.HR > 130))).segments.size() +select jsonb_path_query(:'json'::jsonb, $.track ? (exists(@.segments[*] ? (@.HR > 130))).segments.size()'); + jsonb_path_query +------------------ + 2 This expression returns the size of the track if it contains any segments with high heart rate values, or an empty sequence otherwise. - - PostgreSQL's implementation of the SQL/JSON path - language has the following deviations from the SQL/JSON standard: - + + Devaiations from the SQL Standard + + PostgreSQL's implementation of the SQL/JSON path + language has the following deviations from the SQL/JSON standard: + - - + + Boolean Predicate Path Expressions - A path expression can be a Boolean predicate, although the SQL/JSON - standard allows predicates only in filters. This is necessary for - implementation of the @@ operator. For example, - the following jsonpath expression is valid in - PostgreSQL: + As an extension to the SQL standard, a PostgreSQL + path expression can be a Boolean predicate, whereas the SQL standard allows + predicates only in filters. Where SQL standard path expressions return the + relevant contents of the queried JSON value, predicate path expressions + return the three-value three-valued result of the predicate: + true, false, or + unknown. Compare this filter jsonpath + exression: -$.track.segments[*].HR < 70 +select jsonb_path_query(:'json'::jsonb, '$.track.segments ?(@[*].HR > 130)'); + jsonb_path_query +--------------------------------------------------------------------------------- + {"HR": 135, "location": [47.706, 13.2635], "start time": "2018-10-14 10:39:21"} - - + To a predicate expression, which returns true + +select jsonb_path_query(:'json'::jsonb, '$.track.segments[*].HR > 130'); + jsonb_path_query +------------------ + true + + - - - There are minor differences in the interpretation of regular - expression patterns used in like_regex filters, as - described in . - - - + + Predicate-only path expressions are necessary for implementation of the + @@ operator (and the + jsonb_path_match function), and should not be used + with the @? operator (or + jsonb_path_exists function). + + + + Conversely, non-predicate jsonpath expressions should not be + used with the @@ operator (or the + jsonb_path_match function). + + + + + Regular Expression Interpretation + + There are minor differences in the interpretation of regular + expression patterns used in like_regex filters, as + described in . + + Strict and Lax Modes @@ -17431,18 +17488,30 @@ $.track.segments[*].HR < 70 abstract from the fact that it stores an array of segments when using the lax mode: -lax $.track.segments.location + select jsonb_path_query(:'json'::jsonb, 'lax $.track.segments.location'); + jsonb_path_query +------------------- + [47.763, 13.4034] + [47.706, 13.2635] - In the strict mode, the specified path must exactly match the structure of + In strict mode, the specified path must exactly match the structure of the queried JSON document to return an SQL/JSON item, so using this - path expression will cause an error. To get the same result as in - the lax mode, you have to explicitly unwrap the + path expression will cause an error: + +select jsonb_path_query(:'json'::jsonb, 'strict $.track.segments.location'); +ERROR: jsonpath member accessor can only be applied to an object + + To get the same result as in the lax mode, you have to explicitly unwrap the segments array: -strict $.track.segments[*].location +select jsonb_path_query(:'json'::jsonb, 'strict $.track.segments[*].location'); + jsonb_path_query +------------------- + [47.763, 13.4034] + [47.706, 13.2635] @@ -17451,7 +17520,13 @@ strict $.track.segments[*].location when using the lax mode. For instance, the following query selects every HR value twice: -lax $.**.HR +select jsonb_path_query(:'json'::jsonb, 'lax $.**.HR'); + jsonb_path_query +------------------ + 73 + 135 + 73 + 135 This happens because the .** accessor selects both the segments array and each of its elements, while @@ -17460,7 +17535,11 @@ lax $.**.HR the .** accessor only in the strict mode. The following query selects each HR value just once: -strict $.**.HR +select jsonb_path_query(:'json'::jsonb, 'strict $.**.HR'); + jsonb_path_query +------------------ + 73 + 135