PostgreSQLLa base de données la plus sophistiquée au monde.
Documentation PostgreSQL 15.6 » Langage SQL » Fonctions et opérateurs » Fonctions et opérateurs JSON

9.16. Fonctions et opérateurs JSON

Cette section décrit :

  • les fonctions et opérateurs pour traiter et créer des données JSON

  • le langage de chemin SQL/JSON

Pour en savoir plus sur le standard SQL/JSON, voir [sqltr-19075-6]. Pour des détails sur les types JSON supportés dans PostgreSQL, voir Section 8.14.

9.16.1. Traiter et créer des données JSON

Tableau 9.45 affiche les opérateurs disponibles pour les types de données JSON (voir Section 8.14). De plus, les opérateurs de comparaison habituels indiqués dans Tableau 9.1 sont disponibles pour le type jsonb, mais pas pour le type json. Les opérateurs de comparaison suivent les règles de tri des opérateurs B-tree indiqués dans Section 8.14.4. Voir aussi Section 9.21 pour la fonction d'agrégat json_agg qui agrège les valeurs d'enregistrements sous la forme d'un JSON, pour la fonction d'agrégat json_object_agg qui agrège des paires de valeurs dans un objet JSON, et leurs équivalents jsonb, à savoir jsonb_agg et jsonb_object_agg.

Tableau 9.45. Opérateurs json et jsonb

Opérateur

Description

Exemple(s)

json -> integerjson

jsonb -> integerjsonb

Extrait le n-ième élément d'un tableau JSON (les éléments du tableau sont indexés à partir de zéro, mais les nombres négatifs sont pris en compte à partir de la fin).

'[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json -> 2{"c":"baz"}

'[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json -> -3{"a":"foo"}

json -> textjson

jsonb -> textjsonb

Extrait le champ objet JSON avec la clé donnée.

'{"a": {"b":"foo"}}'::json -> 'a'{"b":"foo"}

json ->> integertext

jsonb ->> integertext

Extrait le n-ième élément d'un tableau JSON, comme le text.

'[1,2,3]'::json ->> 23

json ->> texttext

jsonb ->> texttext

Extrait le champ objet JSON d'après la clé donnée, comme text.

'{"a":1,"b":2}'::json ->> 'b'2

json #> text[]json

jsonb #> text[]jsonb

Extrait le sous-objet JSON d'un chemin spécifié, où les éléments du chemin peuvent être soit les clés d'un champ, soit les indices d'un tableau.

'{"a": {"b": ["foo","bar"]}}'::json #> '{a,b,1}'"bar"

json #>> text[]text

jsonb #>> text[]text

Extrait le sous-objet JSON au chemin spécifié avec text.

'{"a": {"b": ["foo","bar"]}}'::json #>> '{a,b,1}'bar


Note

Les opérateurs d'extraction champ/élément/chemin renvoient NULL, plutôt qu'une erreur, si l'entrée JSON n'a pas la bonne structure correspondant à la requête ; par exemple si la clé ou l'élément du tableau n'existe pas.

Quelques opérateurs supplémentaires existent seulement pour le type jsonb, comme indiqué dans Tableau 9.46. Section 8.14.4 décrit comment ces opérateurs peuvent être utilisés pour rechercher efficacement les données jsonb indexées.

Tableau 9.46. Opérateurs jsonb supplémentaires

Opérateur

Description

Exemple(s)

jsonb @> jsonbboolean

Est-ce que la première valeur JSON contient la seconde ? (Voir Section 8.14.3 pour les détails sur la notion de contenu.)

'{"a":1, "b":2}'::jsonb @> '{"b":2}'::jsonbt

jsonb <@ jsonbboolean

Est-ce que la première valeur JSON est contenue dans la seconde ?

'{"b":2}'::jsonb <@ '{"a":1, "b":2}'::jsonbt

jsonb ? textboolean

Est-ce que la chaîne de caractères existe comme clé de haut niveau ou élément de tableau dans la valeur JSON ?

'{"a":1, "b":2}'::jsonb ? 'b't

'["a", "b", "c"]'::jsonb ? 'b't

jsonb ?| text[]boolean

Est-ce qu'une des chaînes du tableau de texte existe comme clé de haut niveau ou comme élément de tableau ?

'{"a":1, "b":2, "c":3}'::jsonb ?| array['b', 'd']t

jsonb ?& text[]boolean

Est-ce que toutes les chaînes du tableau de texte existent comme clés de haut niveau ou comme éléments de tableau ?

'["a", "b", "c"]'::jsonb ?& array['a', 'b']t

jsonb || jsonbjsonb

Concatène deux valeurs jsonb. Concaténer deux tableaux génère un tableau contenant tous les éléments de chaque entrée. Concaténer deux objets génère un objet contenant l'union de leurs clés, en prenant la valeur du deuxième objet quand il existe deux clés dupliquées. Tous les autres cas sont traités en convertissant une entrée non tableau en un tableau à un seul élément, puis en le traitant comme pour deux tableaux. N'est pas récursif : seul le tableau ou la structure objet de haut niveau est assemblé.

'["a", "b"]'::jsonb || '["a", "d"]'::jsonb["a", "b", "a", "d"]

'{"a": "b"}'::jsonb || '{"c": "d"}'::jsonb{"a": "b", "c": "d"}

'[1, 2]'::jsonb || '3'::jsonb[1, 2, 3]

'{"a": "b"}'::jsonb || '42'::jsonb[{"a": "b"}, 42]

Pour concaténer un tableau à un autre tableau dans une entrée unique, il faut l'envelopper dans une couche supplémentaire de tableau, par exemple :

'[1, 2]'::jsonb || jsonb_build_array('[3, 4]'::jsonb)[1, 2, [3, 4]]

jsonb - textjsonb

Supprime une clé (et sa valeur) à partir d'un objet JSON, ou les valeurs correspondantes de chaînes à partir d'un tableau JSON.

'{"a": "b", "c": "d"}'::jsonb - 'a'{"c": "d"}

'["a", "b", "c", "b"]'::jsonb - 'b'["a", "c"]

jsonb - text[]jsonb

Supprime toutes les clés ou tous les éléments de tableau correspondant à partir de l'opérande gauche.

'{"a": "b", "c": "d"}'::jsonb - '{a,c}'::text[]{}

jsonb - integerjsonb

Supprime l'élément de tableau pour l'index spécifié (les nombres négatifs se décomptent à partir de la fin). Renvoie une erreur si la valeur JSON n'est pas un tableau.

'["a", "b"]'::jsonb - 1 ["a"]

jsonb #- text[]jsonb

Supprime le champ ou l'élément de tableau sur le chemin indiqué, les éléments du chemin pouvant être soit des clés de champ, soit des indices de tableau.

'["a", {"b":1}]'::jsonb #- '{1,b}'["a", {}]

jsonb @? jsonpathboolean

Est-ce que le chemin JSON renvoie tout élément pour la valeur JSON spécifiée ?

'{"a":[1,2,3,4,5]}'::jsonb @? '$.a[*] ? (@ > 2)'t

jsonb @@ jsonpathboolean

Renvoie le résultat d'une vérification de prédicat du chemin JSON pour la valeur JSON indiquée. Seul le premier élément du résultat est pris en compte. Si le résultat n'est pas un booléen, alors NULL est renvoyé.

'{"a":[1,2,3,4,5]}'::jsonb @@ '$.a[*] > 2't


Note

Les opérateurs @? et @@ du type jsonpath suppriment les erreurs suivantes : champ objet ou élément de tableau manquant, type d'élément JSON inattendu, erreurs de date/heure ou de numérique. Les fonctions relatives à jsonpath décrites ci-dessous peuvent aussi supprimer ce type d'erreurs à la demande. Ce comportement pourrait être utile lors de la recherche de collections de documents JSON de différentes structures.

Tableau 9.47 montre les fonctions disponibles pour construire des valeurs json et jsonb.

Tableau 9.47. Fonctions de création de JSON

Fonction

Description

Exemple(s)

to_json ( anyelement ) → json

to_jsonb ( anyelement ) → jsonb

Convertit toute valeur SQL en json ou jsonb. Les tableaux et valeurs composites sont convertis récursivement en tableaux et en objets (les tableaux multidimensionnels deviennent des tableaux de tableaux en JSON). Sinon, s'il existe une conversion entre le type de données SQL et json, la fonction de conversion sera utilisée pour réaliser la conversion ;[a] sinon, une valeur JSON scalaire est produite. Pour tout scalaire autre qu'un nombre, un booléen ou une valeur NULL, la représentation textuelle sera utilisée avec les échappements nécessaires pour la transformer en valeur JSON valide.

to_json('Fred said "Hi."'::text)"Fred said \"Hi.\""

to_jsonb(row(42, 'Fred said "Hi."'::text)){"f1": 42, "f2": "Fred said \"Hi.\""}

array_to_json ( anyarray [, boolean ] ) → json

Convertit un tableau SQL en tableau JSON. Le comportement est le même que to_json sauf que des sauts de ligne seront ajoutés entre les éléments de tableau de haut niveau si le paramètre booléen optionnel vaut true.

array_to_json('{{1,5},{99,100}}'::int[])[[1,5],[99,100]]

row_to_json ( record [, boolean ] ) → json

Convertit une valeur composite SQL en objet JSON. Le comportement est le même que to_json sauf que des sauts de ligne seront ajoutés entre les éléments de tableau de haut niveau si le paramètre booléen optionnel vaut true.

row_to_json(row(1,'foo')){"f1":1,"f2":"foo"}

json_build_array ( VARIADIC "any" ) → json

jsonb_build_array ( VARIADIC "any" ) → jsonb

Construit un tableau JSON avec des types potentiellement hétérogènes à partir d'une liste d'arguments de longueur variable. Chaque argument est converti avec la fonction to_json ou to_jsonb.

json_build_array(1, 2, 'foo',4,5)[1, 2, "foo", 4, 5]

json_build_object ( VARIADIC "any" ) → json

jsonb_build_object ( VARIADIC "any" ) → jsonb

Construit un objet JSON à partir d'une liste d'arguments de longueur indéfinie. Par convention, la liste d'arguments consiste en des clés et valeurs en alternance. Les arguments clés sont convertis en texte ; les arguments valeurs sont convertis via les fonctions to_json ou to_jsonb.

json_build_object('foo', 1, 2, row(3, 'bar')){"foo" : 1, "2" : {"f1":3,"f2":"bar"}}

json_object ( text[] ) → json

jsonb_object ( text[] ) → jsonb

Construit un objet JSON à partir d'un tableau de texte. Le tableau doit avoir soit exactement une dimension avec un nombre pair de membres, auquel cas ils sont pris comme des paires alternantes clé/valeur, ou deux dimensions de telle façon que le tableau interne a exactement deux éléments, pris comme une paire clé/valeur. Toutes les valeurs sont converties en chaîne JSON.

json_object('{a, 1, b, "def", c, 3.5}'){"a" : "1", "b" : "def", "c" : "3.5"}

json_object('{{a, 1}, {b, "def"}, {c, 3.5}}'){"a" : "1", "b" : "def", "c" : "3.5"}

json_object ( keys text[], values text[] ) → json

jsonb_object ( keys text[], values text[] ) → jsonb

Cette forme de json_object prend les clés et valeurs à partir de tableaux de texte séparés. Pour le reste, elle est identique à la forme à un argument.

json_object('{a, b}', '{1,2}'){"a": "1", "b": "2"}

[a] Par exemple, l'extension hstore contient une conversion de hstore vers json, pour que les valeurs hstore converties par les fonctions de création JSON soient représentées en tant qu'objets JSON, et non pas comme des valeurs de type chaîne de caractères.


Tableau 9.48 montre les fonctions disponibles pour le traitement de valeurs json et jsonb.

Tableau 9.48. Fonctions de traitement JSON

Fonction

Description

Exemple(s)

json_array_elements ( json ) → setof json

jsonb_array_elements ( jsonb ) → setof jsonb

Étend le tableau JSON de haut niveau en un ensemble de valeurs JSON.

select * from json_array_elements('[1,true, [2,false]]')

   value
-----------
 1
 true
 [2,false]
       

json_array_elements_text ( json ) → setof text

jsonb_array_elements_text ( jsonb ) → setof text

Étend le tableau JSON de haut niveau en un ensemble de valeurs de type text.

select * from json_array_elements_text('["foo", "bar"]')

   value
-----------
 foo
 bar
       

json_array_length ( json ) → integer

jsonb_array_length ( jsonb ) → integer

Renvoie le nombre d'éléments dans le tableau JSON de haut niveau.

json_array_length('[1,2,3,{"f1":1,"f2":[5,6]},4]')5

jsonb_array_length('[]')0

json_each ( json ) → setof record ( key text, value json )

jsonb_each ( jsonb ) → setof record ( key text, value jsonb )

Étend l'objet JSON de haut niveau en un ensemble de paires clé/valeur.

select * from json_each('{"a":"foo", "b":"bar"}')

 key | value
-----+-------
 a   | "foo"
 b   | "bar"
       

json_each_text ( json ) → setof record ( key text, value text )

jsonb_each_text ( jsonb ) → setof record ( key text, value text )

Étend l'objet JSON de haut niveau en un ensemble de paires clé/valeur. Les value renvoyées seront de type text.

select * from json_each_text('{"a":"foo", "b":"bar"}')

 key | value
-----+-------
 a   | foo
 b   | bar
       

json_extract_path ( from_json json, VARIADIC path_elems text[] ) → json

jsonb_extract_path ( from_json jsonb, VARIADIC path_elems text[] ) → jsonb

Extrait un sous-objet JSON au chemin spécifié. (Ceci est fonctionnellement équivalent à l'opérateur #>, mais écrire le chemin sous la forme d'une liste peut être plus agréable dans certains cas.)

json_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}', 'f4', 'f6')"foo"

json_extract_path_text ( from_json json, VARIADIC path_elems text[] ) → text

jsonb_extract_path_text ( from_json jsonb, VARIADIC path_elems text[] ) → text

Extrait le sous-objet JSON au chemin spécifié sous la forme d'un text. (Ceci est équivalent fonctionnement à l'opérateur #>>.)

json_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}', 'f4', 'f6')foo

json_object_keys ( json ) → setof text

jsonb_object_keys ( jsonb ) → setof text

Renvoie l'ensemble de clés dans l'objet JSON de haut niveau.

select * from json_object_keys('{"f1":"abc","f2":{"f3":"a", "f4":"b"}}')

 json_object_keys
------------------
 f1
 f2
       

json_populate_record ( base anyelement, from_json json ) → anyelement

jsonb_populate_record ( base anyelement, from_json jsonb ) → anyelement

Étend l'objet JSON de haut niveau en une ligne ayant le type composite de l'argument base. L'objet JSON est parcouru pour y trouver les champs dont le nom correspond aux noms de colonnes du type de la ligne en sortie, et leurs valeurs sont insérées dans ces colonnes en sortie. (Les champs qui ne correspondent à aucun nom de colonne en sortie sont ignorés.) Dans le cas d'une utilisation typique, la valeur de base est simplement NULL, ce qui signifie que toute colonne en sortie qui ne correspond pas à un champ d'objet sera remplie avec un NULL. Néanmoins, si base ne vaut pas NULL, alors les valeurs qu'il contient seront utilisées pour les colonnes sans correspondance.

Pour convertir une valeur JSON au type SQL d'une colonne en sortie, les règles suivantes sont appliquées sur cette séquence :

  • Une valeur JSON null est convertie en NULL SQL dans tous les cas.

  • Si la colonne en sortie est de type json ou jsonb, la valeur JSON est reproduite exactement.

  • Si la colonne en sortie est un type (de ligne) composite, et que la valeur JSON est un objet JSON, les champs de l'objet sont convertis en colonnes du type de ligne par application récursive de ces règles.

  • De la même façon, si la colonne en sortie est un type tableau et que la valeur JSON est un tableau JSON, les éléments du tableau JSON sont convertis en éléments du tableau en sortie par application récursive de ces règles.

  • Sinon, si la valeur JSON est une chaîne, le contenu de la chaîne est donné à la fonction de conversion en entrée pour le type de données de la colonne.

  • Sinon, la représentation textuelle habituelle de la valeur JSON est envoyée à la fonction de conversion en entrée pour le type de données de la colonne.

Bien que l'exemple ci-dessous utilise une valeur constante JSON, une utilisation typique serait de référencer une colonne json ou jsonb latéralement d'une autre table dans la clause FROM de la requête. Écrire json_populate_record dans la clause FROM est une bonne pratique, car toutes les colonnes extraites sont utilisables sans avoir à faire des appels dupliqués à la fonction.

create type subrowtype as (d int, e text); create type myrowtype as (a int, b text[], c subrowtype);

select * from json_populate_record(null::myrowtype, '{"a": 1, "b": ["2", "a b"], "c": {"d": 4, "e": "a b c"}, "x": "foo"}')

 a |   b       |      c
---+-----------+-------------
 1 | {2,"a b"} | (4,"a b c")
       

json_populate_recordset ( base anyelement, from_json json ) → setof anyelement

jsonb_populate_recordset ( base anyelement, from_json jsonb ) → setof anyelement

Étend le tableau JSON de haut niveau composé d'objets en un ensemble de lignes ayant le type composite de l'argument base. Chaque élément du tableau JSON est traité comme décrit ci-dessus pour json[b]_populate_record.

create type twoints as (a int, b int);

select * from json_populate_recordset(null::twoints, '[{"a":1,"b":2}, {"a":3,"b":4}]')

 a | b
---+---
 1 | 2
 3 | 4
       

json_to_record ( json ) → record

jsonb_to_record ( jsonb ) → record

Étend l'objet JSON de haut niveau en une ligne ayant le type composite défini par une clause AS. (Comme avec toutes les fonctions renvoyant record, la requête appelante doit explicitement définir la structure de l'enregistrement avec une clause AS.) L'enregistrement en sortie est rempli avec les champs de l'objet JSON, de la même façon que décrite ci-dessus pour json[b]_populate_record. Comme il n'existe aucune valeur record en entrée, les colonnes sans correspondance sont remplies avec des NULL.

create type myrowtype as (a int, b text);

select * from json_to_record('{"a":1, "b":[1,2,3], "c":[1,2,3], "e":"bar", "r": {"a": 123, "b": "a b c"}}') as x(a int, b text, c int[], d text, r myrowtype)

 a |    b    |    c    | d |       r
---+---------+---------+---+---------------
 1 | [1,2,3] | {1,2,3} |   | (123,"a b c")
       

json_to_recordset ( json ) → setof record

jsonb_to_recordset ( jsonb ) → setof record

Étend le tableau JSON de haut niveau composé d'objets en un ensemble de lignes ayant le type composite défini par une clause AS. (Comme avec toutes les fonctions renvoyant record, la requête appelante doit explicitement définir la structure de l'enregistrement avec une clause AS.) Chaque élément du tableau JSON est traité comme décrit ci-dessus pour json[b]_populate_record.

select * from json_to_recordset('[{"a":1,"b":"foo"}, {"a":"2","c":"bar"}]') as x(a int, b text)

 a |  b
---+-----
 1 | foo
 2 |
       

jsonb_set ( target jsonb, path text[], new_value jsonb [, create_if_missing boolean ] ) → jsonb

Renvoie target avec l'élément désigné par path remplacé par new_value ou avec new_value ajouté si create_if_missing vaut true (ce qui est la valeur par défaut) et si l'élément désigné par path n'existe pas. Toutes les étapes précédentes dans le chemin doivent exister, sinon le target est renvoyé intact. Comme avec les opérateurs orientés chemin, les entiers négatifs qui apparaissent dans path se décomptent à partir de la fin des tableaux JSON. Si l'étape du dernier chemin est un index inexistant (hors limite) du tableau et si create_if_missing vaut true, la nouvelle valeur est ajoutée au début du tableau si l'index est négatif et à la fin du tableau s'il est positif.

jsonb_set('[{"f1":1,"f2":null},2,null,3]', '{0,f1}','[2,3,4]', false)[{"f1": [2, 3, 4], "f2": null}, 2, null, 3]

jsonb_set('[{"f1":1,"f2":null},2]', '{0,f3}', '[2,3,4]')[{"f1": 1, "f2": null, "f3": [2, 3, 4]}, 2]

jsonb_set_lax ( target jsonb, path text[], new_value jsonb [, create_if_missing boolean [, null_value_treatment text ]] ) → jsonb

Si new_value n'est pas NULL, se comporte de façon identique à jsonb_set. Sinon se comporte suivant la valeur de null_value_treatment qui doit être parmi 'raise_exception', 'use_json_null', 'delete_key' ou 'return_target'. Par défaut, il s'agit de 'use_json_null'.

jsonb_set_lax('[{"f1":1,"f2":null},2,null,3]', '{0,f1}', null)[{"f1": null, "f2": null}, 2, null, 3]

jsonb_set_lax('[{"f1":99,"f2":null},2]', '{0,f3}', null, true, 'return_target')[{"f1": 99, "f2": null}, 2]

jsonb_insert ( target jsonb, path text[], new_value jsonb [, insert_after boolean ] ) → jsonb

Renvoie target avec new_value inséré. Si l'élément désigné par path est un élément de tableau, new_value sera inséré avant cet élément si insert_after vaut false (ce qui est la valeur par défaut) ou après si insert_after vaut true. Si l'élément désigné par path est un champ objet, new_value sera inséré seulement si l'objet ne contient pas déjà cette clé. Toutes les étapes précédentes dans le chemin doivent exister, sinon target est renvoyé non modifié. Comme avec les opérateurs orientés chemin, les nombres négatifs qui apparaissent dans path sont décomptés à partir de la fin des tableaux JSON. Si la dernière étape du chemin est un index hors limite de tableau, la nouvelle valeur est ajoutée au début du tableau si l'index est négatif ou à la fin du tableau s'il est positif.

jsonb_insert('{"a": [0,1,2]}', '{a, 1}', '"new_value"'){"a": [0, "new_value", 1, 2]}

jsonb_insert('{"a": [0,1,2]}', '{a, 1}', '"new_value"', true){"a": [0, 1, "new_value", 2]}

json_strip_nulls ( json ) → json

jsonb_strip_nulls ( jsonb ) → jsonb

Supprime tous les champs objets ayant des valeurs NULL à partir de la valeur JSON donnée, de façon récurvise. Les valeurs NULL qui ne sont pas des champs objets ne sont pas touchées.

json_strip_nulls('[{"f1":1, "f2":null}, 2, null, 3]')[{"f1":1},2,null,3]

jsonb_path_exists ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → boolean

Vérifie si le chemin JSON renvoie des éléments de la valeur JSON spécifiée. Si l'argument vars est indiqué, il doit correspondre à un objet JSON, et ses champs fournissent des valeurs nommées à substituer dans l'expression jsonpath. Si l'argument silent est indiqué et vaut true, la fonction supprime les mêmes erreurs que les opérateurs @? et @@.

jsonb_path_exists('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2,"max":4}')t

jsonb_path_match ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → boolean

Renvoie le résultat de la vérification d'un prédicat de chemin JSON pour la valeur JSON spécifiée. Seul le premier élément du résultat est pris en compte. Si le résultat n'est pas un booléen, alors NULL est renvoyé. Les arguments optionnels vars et silent agissent de la même façon que pour jsonb_path_exists.

jsonb_path_match('{"a":[1,2,3,4,5]}', 'exists($.a[*] ? (@ >= $min && @ <= $max))', '{"min":2,"max":4}')t

jsonb_path_query ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → setof jsonb

Renvoie tous les éléments JSON renvoyés par le chemin JSON pour la valeur JSON spécifiée. Les arguments optionnels vars et silent agissent de la même façon que pour jsonb_path_exists.

select * from jsonb_path_query('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2,"max":4}')

 jsonb_path_query
------------------
 2
 3
 4
       

jsonb_path_query_array ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → jsonb

Renvoie tous les éléments JSON renvoyés par le chemin JSON pour la valeur JSON spécifiée, sous la forme d'un tableau JSON. Les arguments optionnels vars et silent agissent de la même façon que pour jsonb_path_exists.

jsonb_path_query_array('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2, "max":4}')[2, 3, 4]

jsonb_path_query_first ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → jsonb

Renvoie le premier élément JSON renvoyé par le chemin JSON pour la valeur JSON spécifiée. Renvoie NULL s'il n'y a pas de résultat. Les arguments optionnels vars et silent agissent de la même façon que pour jsonb_path_exists.

jsonb_path_query_first('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2, "max":4}')2

jsonb_path_exists_tz ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → boolean

jsonb_path_match_tz ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → boolean

jsonb_path_query_tz ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → setof jsonb

jsonb_path_query_array_tz ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → jsonb

jsonb_path_query_first_tz ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → jsonb

Ces fonctions agissent comme leurs homologues décrits ci-dessus sans le suffixe _tz, sauf que ces fonctions acceptent la comparaison de valeurs date/heure qui nécessitent des conversions adaptées suivant le fuseau horaire. L'exemple ci-dessous requiert l'interprétation de la valeur date seule 2015-08-02 comme un horodatage avec fuseau horaire, pour que le résultat dépende du paramétrage actuel de TimeZone. Du fait de cette dépendance, ces fonctions sont marquées stables, ce qui signifie que ces fonctions ne peuvent pas être utilisées dans les index. Leurs homologues sont immuables, et donc peuvent être utilisés dans les index ; cependant, elles renverront des erreurs si on leur demande ce type de comparaison.

jsonb_path_exists_tz('["2015-08-01 12:00:00-05"]', '$[*] ? (@.datetime() < "2015-08-02".datetime())')t

jsonb_pretty ( jsonb ) → text

Convertit la valeur JSON donnée en un texte proprement indenté.

jsonb_pretty('[{"f1":1, "f2":null}, 2]')

[
    {
        "f1": 1,
        "f2": null
    },
    2
]
       

json_typeof ( json ) → text

jsonb_typeof ( jsonb ) → text

Renvoie le type de la valeur JSON de haut niveau sous la forme d'une chaîne de caractères. Les types possibles sont object, array, string, number, boolean et null. (Le résultat null ne doit pas être pris pour un NULL SQL ; voir les exemples.)

json_typeof('-123.4')number

json_typeof('null'::json)null

json_typeof(NULL::json) IS NULLt


9.16.2. Le langage de chemin SQL/JSON

Les expressions de chemin SQL/JSON indiquent les éléments à récupérer à partir de données JSON, similaires aux expressions XPath utilisées pour l'accès SQL au XML. Dans PostgreSQL, les expressions de chemin sont implémentées sous la forme du type de données jsonpath et peuvent utiliser tout élément décrit dans Section 8.14.7.

Les fonctions et opérateurs de requêtes JSON passent l'expression de chemin fournie au moteur de chemin pour évaluation. Si l'expression correspond à la donnée JSON requêtée, l'élément JSON correspondant ou l'ensemble d'éléments est renvoyé. Les expressions de chemin sont écrites dans le langage de chemin SQL/JSON et peuvent inclure les expressions et fonctions arithmétiques.

Une expression de chemin consiste en une séquence d'éléments autorisés par le type de données jsonpath. L'expression de chemin est habituellement évaluée de gauche à droite, mais vous pouvez utiliser les parenthèses pour modifier l'ordre des opérations. Si l'évaluation réussit, une séquence d'éléments JSON est produite et le résultat de l'évaluation est renvoyé à la fonction de requête JSON qui termine le traitement indiqué.

Pour faire référence à la valeur JSON en cours de requêtage (l'élément de contexte), utilisez la variable $ dans l'expression de chemin. Elle peut être suivie par un ou plusieurs opérateurs d'accesseurs, qui descendent dans la structure JSON, étape par étape, pour récupérer les sous-éléments de l'élément de contexte. Chaque opérateur qui suit traite le résultat de l'étape d'évaluation précédente.

Par exemple, supposez que vous ayez certaines données JSON à partir d'un traqueur GPS que vous voulez analyser, tel que :

{
  "track": {
    "segments": [
      {
        "location":   [ 47.763, 13.4034 ],
        "start time": "2018-10-14 10:05:14",
        "HR": 73
      },
      {
        "location":   [ 47.706, 13.2635 ],
        "start time": "2018-10-14 10:39:21",
        "HR": 135
      }
    ]
  }
}
  

Pour récupérer les segments de piste disponibles, vous avez besoin d'utiliser l'opérateur d'accesseur .key pour descendre à travers les objets JSON tout autour :

$.track.segments
  

Pour récupérer le contenu d'un tableau, vous utilisez typiquement l'opérateur [*]. Par exemple, le chemin suivant renverra les coordonnées d'emplacement pour tous les segments de piste disponibles :

$.track.segments[*].location
  

Pour renvoyer les coordonnées du premier segment seulement, vous pouvez indiquer l'indice correspondant dans l'opérateur []. Rappellez-vous que les indices de tableau JSON commencent à 0 :

$.track.segments[0].location
  

Le résultat de chaque étape d'évaluation de chemin peut être traité par un ou plusieurs opérateurs et méthodes jsonpath, listés dans Section 9.16.2.2. Chaque nom de méthode doit être précédé d'un point. Par exemple, vous pouvez obtenir la taille d'un tableau :

$.track.segments.size()
  

D'autres exemples d'utilisation d'opérateurs et méthodes jsonpath à l'intérieur d'expressions de chemins apparaissent ci-dessous dans Section 9.16.2.2.

Lors de la définition d'un chemin, vous pouvez aussi utiliser une ou plusieurs expressions de filtre qui fonctionnent de façon similaire à la clause WHERE en SQL. Une expression de filtre commence avec un point d'interrogation et fournit une condition entre parenthèses :

? (condition)
  

Les expressions de filtre doivent être écrites juste après l'étape d'évaluation du chemin auquel elles s'appliquent. Le résultat de cette étape est filtré pour inclure seulement les éléments qui satisfont la condition fournie. SQL/JSON définit une logique à trois valeurs, donc la condition peut valoir true, false ou unknown. La valeur unknown joue le même rôle que le NULL SQL et peut être testée avec le prédicat is unknown. Les étapes suivantes d'évaluation du chemin utilisent seulement les éléments pour lesquels l'expression de filtre renvoie true.

Les fonctions et opérateurs pouvant être utilisés dans des expressions de filtre sont listés dans Tableau 9.50. À l'intérieur d'une expression de filtre, la variable @ dénote la valeur en cours de filtrage (un résultat de l'étape de chemin précédente). Vous pouvez écrire les opérateurs d'accesseurs après @ pour récupérer les éléments du composant.

Par exemple, supposez que vous vouliez récupérer toutes les valeurs de fréquence cardiaque supérieures à 130. Vous pouvez le faire en utilisant l'expression suivante :

$.track.segments[*].HR ? (@ > 130)
  

Pour obtenir les heures de début des segments ayant une telle valeur, vous devez filtrer les segments incompatiables avant de renvoyer les heures de début, donc l'expression de filtre est appliquée à l'étape précédente, et le chemin utilisé dans la condition est différent :

$.track.segments[*] ? (@.HR > 130)."start time"
  

Vous pouvez utiliser plusieurs expressions de filtre en séquence, si nécessaire. Par exemple, l'expression suivante sélectionne les heures de début de tous les segments qui contiennent des emplacements avec les bonnes coordonnées et les valeurs hautes de fréquence cardiaque :

$.track.segments[*] ? (@.location[1] < 13.4) ? (@.HR > 130)."start time"
  

Il est aussi autorisé d'utiliser des expressions de filtre à différents niveaux de profondeur. L'exemple suivant filtre tout d'abord tous les segments par emplacement, puis renvoie les valeurs hautes de fréquence cardiaque sur ces segments, si disponibles :

$.track.segments[*] ? (@.location[1] < 13.4).HR ? (@ > 130)
  

Vous pouvez aussi imbriquer les expressions de filtre :

$.track ? (exists(@.segments[*] ? (@.HR > 130))).segments.size()
  

Cette expression renvoie la taille de la trace si elle contient des segments avec des valeurs hautes de fréquence cardiaque ou, sinon, une séquence vide.

L'implémentation PostgreSQL du langage de chemin SQL/JSON présente les différences suivantes sur le standard SQL/JSON :

  • Une expression de chemin peut être un prédicat booléen, bien que le standard SQL/JSON autorise les prédicats uniquement dans les filtres. Ceci est nécessaire pour l'implémentation de l'opérateur @@. Par exemple, l'expression jsonpath suivante est valide dans PostgreSQL :

    $.track.segments[*].HR < 70
        

  • Il existe des différences mineures dans l'interprétation des motifs d'expression rationnelle utilisés dans les filtres like_regex, comme décrit dans Section 9.16.2.3.

9.16.2.1. Modes strict et permissif

Quand vous requêtez des données JSON, l'expression de chemin pourrait ne pas correspondre à la structure de données JSON actuelle. Une tentative d'accéder à un membre inexistant d'un objet ou d'un élément d'un tableau résulterait en une erreur de structure. Les expressions de chemin SQL/JSON ont deux modes pour la gestion des erreurs de structure :

  • lax (permissif, par défaut) -- le moteur de chemin adapte implicitement la donnée requêtée au chemin spécifié. Toute erreur de structure restante est supprimée et convertie en des séquences SQL/JSON vides.

  • strict -- si une erreur de structure survient, une erreur est levée.

Le mode permissif facilite la correspondance de la structure d'un document JSON et celle d'une expression de chemin si la donnée JSON n'est pas conforme au schéma attendu. Si un opérande ne correspond pas aux demandes d'une opération particulière, il peut être automatiquement intégré à un tableau SQL/JSON ou déballé en convertissant ses éléments en une séquence SQL/JSON avant de réaliser cette opération. De plus, les opérateurs de comparaison déballent automatiquement leurs opérandes dans le mode permissif, donc vous pouvez directement comparer les tableaux SQL/JSON. Un tableau de taille 1 est considéré égal à son seul élément. Le déballage automatique n'est pas réaliser si :

  • L'expression de chemin contient les méthodes type() ou size() qui renvoient respectivement le type et le nombre d'éléments dans le tableau.

  • Les données JSON requêtées contiennent des tableaux imbriqués. Dans ce cas, seul le tableau externe est déballé alors que les tableaux internes restent inchangés. De ce fait, le déballage implicite peut seulement descendre d'un niveau à chaque étape d'évaluation du chemin.

Par exemple, lors du requêtage de données GPS ci-dessus, vous pouvez faire abstraction du fait qu'il stocke un tableau de segments en utilisant le mode permissif :

lax $.track.segments.location
   

Dans le mode strict, le chemin spécifié doit correspondre exactement à la structure du document JSON requêté pour renvoyer un élément SQL/JSON, donc utiliser cette expression de chemin causera une erreur. Pour obtenir le même résultat que dans le mode permissif, vous devez explicitement déballer le tableau segments :

strict $.track.segments[*].location
   

L'accesseur .** peut apporter des résultats surprenants lors de l'utilisation du mode non strict. Par exemple, la requête suivante sélectionne chaque valeur HR deux fois :

lax $.**.HR

Ceci survient parce que l'accesseur .** sélectionne à la fois le tableau de segments et chacun de ses éléments, alors que l'accesseur .HR déballe automatiquement les tableaux lors de l'utilisation du mode non strict. Pour éviter des résultats surprenants, nous recommandons d'utiliser l'accesseur .** uniquement dans le mode strict. la requête suivant sélectionne chaque valeur HR une seule fois :

strict $.**.HR

9.16.2.2. Opérateurs et méthodes de chemin SQL/JSON

Tableau 9.49 montre les opérateurs et méthodes disponibles pour jsonpath. Notez que, bien que les opérateurs et méthodes unaires puissent être appliqués à de nombreuses valeurs résultant d'une étape de chemin précédente, les opérateurs binaires (addition etc.) peuvent seulement être appliqués à des valeurs seules.

Tableau 9.49. Opérateurs et méthodes jsonpath

Opérateur/Méthode

Description

Exemple(s)

number + numbernumber

Addition

jsonb_path_query('[2]', '$[0] + 3')5

+ numbernumber

Plus unaire (pas d'opération) ; contrairement à l'addition, ceci peut itérer sur plusieurs valeurs

jsonb_path_query_array('{"x": [2,3,4]}', '+ $.x')[2, 3, 4]

number - numbernumber

Soustraction

jsonb_path_query('[2]', '7 - $[0]')5

- numbernumber

Négation ; contrairement à la soustraction, ceci peut itérer sur plusieurs valeurs

jsonb_path_query_array('{"x": [2,3,4]}', '- $.x')[-2, -3, -4]

number * numbernumber

Multiplication

jsonb_path_query('[4]', '2 * $[0]')8

number / numbernumber

Division

jsonb_path_query('[8.5]', '$[0] / 2')4.2500000000000000

number % numbernumber

Modulo (reste)

jsonb_path_query('[32]', '$[0] % 10')2

value . type()string

Type de l'élément JSON (voir json_typeof)

jsonb_path_query_array('[1, "2", {}]', '$[*].type()')["number", "string", "object"]

value . size()number

Taille de l'élément JSON (nombre d'éléments d'un tableau, ou 1 si ce n'est pas un tableau)

jsonb_path_query('{"m": [11, 15]}', '$.m.size()')2

value . double()number

Nombre flottant approximatif converti en nombre JSON ou en chaîne

jsonb_path_query('{"len": "1.9"}', '$.len.double() * 2')3.8

number . ceiling()number

Entier le plus proche, plus grand ou égal au nombre donné

jsonb_path_query('{"h": 1.3}', '$.h.ceiling()')2

number . floor()number

Entier le plus proche, plus petit ou égal au nombre donné

jsonb_path_query('{"h": 1.7}', '$.h.floor()')1

number . abs()number

Valeur absolue du nombre donné

jsonb_path_query('{"z": -0.3}', '$.z.abs()')0.3

string . datetime()datetime_type (voir note)

Valeur date/heure convertie en chaîne

jsonb_path_query('["2015-8-1", "2015-08-12"]', '$[*] ? (@.datetime() < "2015-08-2".datetime())')"2015-8-1"

string . datetime(template)datetime_type (voir note)

Valeur date/heure convertie en une chaîne en utilisant le modèle to_timestamp indiqué

jsonb_path_query_array('["12:30", "18:40"]', '$[*].datetime("HH24:MI")')["12:30:00", "18:40:00"]

object . keyvalue()array

Les paires clé-valeur de l'objet, représentées sous la forme d'un tableau d'objets contenant trois champs : "key", "value" et "id" ; "id" est un identifiant unique de l'objet auquel la paire clé-valeur appartient

jsonb_path_query_array('{"x": "20", "y": 32}', '$.keyvalue()')[{"id": 0, "key": "x", "value": "20"}, {"id": 0, "key": "y", "value": 32}]


Note

Le type de résultat des méthodes datetime() et datetime(template) peut être date, timetz, time, timestamptz ou timestamp. Les deux méthodes déterminent dynamiquement le type du résultat.

La méthode datetime() trie en séquence pour faire correspondre sa chaîne en entrée aux formats ISO pour les types date, timetz, time, timestamptz et timestamp. Elle s'arrête au premier format correspondant et émet le type de données correspondant.

La méthode datetime(template) détermine le type de résultat suivant les champs utilisés dans la chaîne modèle fournie.

Les méthodes datetime() et datetime(template) utilisent les mêmes règles d'analyse que la fonction SQL to_timestamp (voir Section 9.8), avec trois exceptions. Tout d'abord, ces méthodes n'autorisent pas les motifs de modèle sans correspondance. Ensuite, seuls les séparateurs suivants sont autorisés dans la chaîne modèle : signe moins, point, barre oblique, virgule, apostrophe, point-virgule, deux-points et espace. Enfin, les séparateurs dans la chaîne modèle doivent correspondre exactement à la chaîne en entrée.

Si différents types date/heure doivent être comparés, une conversion implicite est appliquée. Une valeur date peut être convertie en timestamp ou timestamptz, une valeur timestamp peut être convertie en timestamptz, et une valeur time en timetz. Néanmoins, toutes sauf la première de ces conversions dépendent du paramétrage actuel de TimeZone, et de ce fait peuvent seulement être réalisées à travers les fonctions jsonpath sensibles au fuseau horaire.

Tableau 9.50 montre les éléments d'expression de filtre disponibles.

Tableau 9.50. Éléments d'expression de filtre jsonpath

Prédicat/valeur

Description

Exemple(s)

value == valueboolean

Comparaison d'égalité (ceci, et les autres opérateurs de comparaison, fonctionnent sur toutes les valeurs scalaires JSON)

jsonb_path_query_array('[1, "a", 1, 3]', '$[*] ? (@ == 1)')[1, 1]

jsonb_path_query_array('[1, "a", 1, 3]', '$[*] ? (@ == "a")')["a"]

value != valueboolean

value <> valueboolean

Comparaison de non égalité

jsonb_path_query_array('[1, 2, 1, 3]', '$[*] ? (@ != 1)')[2, 3]

jsonb_path_query_array('["a", "b", "c"]', '$[*] ? (@ <> "b")')["a", "c"]

value < valueboolean

Comparaison inférieur

jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ < 2)')[1]

value <= valueboolean

Comparaison inférieur ou égal

jsonb_path_query_array('["a", "b", "c"]', '$[*] ? (@ <= "b")')["a", "b"]

value > valueboolean

Comparaison supérieur

jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ > 2)')[3]

value >= valueboolean

Comparaison supérieur ou égal

jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ >= 2)')[2, 3]

trueboolean

Constante JSON true

jsonb_path_query('[{"name": "John", "parent": false}, {"name": "Chris", "parent": true}]', '$[*] ? (@.parent == true)'){"name": "Chris", "parent": true}

falseboolean

Constante JSON false

jsonb_path_query('[{"name": "John", "parent": false}, {"name": "Chris", "parent": true}]', '$[*] ? (@.parent == false)'){"name": "John", "parent": false}

nullvalue

Constante JSON null (notez que, contrairement au SQL, la comparaison avec null fonctionne normalement)

jsonb_path_query('[{"name": "Mary", "job": null}, {"name": "Michael", "job": "driver"}]', '$[*] ? (@.job == null) .name')"Mary"

boolean && booleanboolean

AND booléen

jsonb_path_query('[1, 3, 7]', '$[*] ? (@ > 1 && @ < 5)')3

boolean || booleanboolean

OR booléen

jsonb_path_query('[1, 3, 7]', '$[*] ? (@ < 1 || @ > 5)')7

! booleanboolean

NOT booléen

jsonb_path_query('[1, 3, 7]', '$[*] ? (!(@ < 5))')7

boolean is unknownboolean

Teste si une condition booléenne est unknown.

jsonb_path_query('[-1, 2, 7, "foo"]', '$[*] ? ((@ > 0) is unknown)')"foo"

string like_regex string [ flag string ] → boolean

Teste si le premier opérande correspond à l'expression rationnelle donnée par le deuxième opérande, optionnellement avec les modifications décrites par une chaîne avec les caractères de flag (voir Section 9.16.2.3).

jsonb_path_query_array('["abc", "abd", "aBdC", "abdacb", "babc"]', '$[*] ? (@ like_regex "^ab.*c")')["abc", "abdacb"]

jsonb_path_query_array('["abc", "abd", "aBdC", "abdacb", "babc"]', '$[*] ? (@ like_regex "^ab.*c" flag "i")')["abc", "aBdC", "abdacb"]

string starts with stringboolean

Teste si le deuxième opérande est une sous-chaîne initiale du premier opérande.

jsonb_path_query('["John Smith", "Mary Stone", "Bob Johnson"]', '$[*] ? (@ starts with "John")')"John Smith"

exists ( path_expression )boolean

Teste si une expression de chemin correspond à au moins un élément SQL/JSON. Renvoie unknown si l'expression de chemin retourne une erreur ; le deuxième exemple utilise ceci pour éviter une erreur de clé inexistante dans le mode strict.

jsonb_path_query('{"x": [1, 2], "y": [2, 4]}', 'strict $.* ? (exists (@ ? (@[*] > 2)))')[2, 4]

jsonb_path_query_array('{"value": 41}', 'strict $ ? (exists (@.name)) .name')[]


9.16.2.3. Expressions rationnelles SQL/JSON

Les expressions de chemin SQL/JSON permettent la correspondance de texte selon une expression rationnelle avec le filtre like_regex. Par exemple, la requête de chemin SQL/JSON suivante correspondrait, sans sensibilité à la casse, à toutes les chaînes d'un tableau commençant avec une voyelle anglaise :

$[*] ? (@ like_regex "^[aeiou]" flag "i")
   

La chaîne optionnelle flag pourrait inclure un ou plusieurs caractères : i pour une recherche insensible à la casse, m pour autoriser ^ et $ à correspondre aux nouvelles lignes, s pour autoriser . à correspondre à une nouvelle ligne, et q pour englober le motif complet (réduisant le comportement à une simple correspondance de sous-chaîne).

Le standard SQL/JSON emprunte sa définition d'expressions rationnelles de l'opérateur LIKE_REGEX qui, à son tour, utilise le standard XQuery. PostgreSQL n'accepte pas actuellement l'opérateur LIKE_REGEX. De ce fait, le filtre like_regex est implémenté en utilisant le moteur d'expression rationnelle POSIX décrit dans Section 9.7.3. Ceci amène différentes variations mineures du comportement du standard SQL/JSON, listées dans Section 9.7.3.8. Notez, néanmoins, que les incompatibilités au niveau des lettres du drapeau décrites ici ne s'appliquent pas à SQL/JSON, car elles traduisent les lettres drapeau de XQuery pour correspondre à ce que le moteur POSIX attend.

Gardez en tête que l'argument motif de like_regex est une chaîne littérale de chemin JSON, écrite suivant les règles données dans Section 8.14.7. Ceci signifie en particulier que tout antislash utilisé dans l'expression rationnelle doit être doublé. Par exemple, pour établir une correspondance aux valeurs de type chaîne de caractères du document racine ne contenant que des chiffres :

$.* ? (@ like_regex "^\\d+$")