J'ai une table dans une base de données postgresql 9.4 avec un champ jsonb appelé récepteurs. Quelques exemples de lignes:
[{"id": "145119603", "name": "145119603", "type": 2}]
[{"id": "1884595530", "name": "1884595530", "type": 1}]
[{"id": "363058213", "name": "363058213", "type": 1}]
[{"id": "1427965764", "name": "1427965764", "type": 1}]
[{"id": "193623800", "name": "193623800", "type": 0}, {"id": "419955814", "name": "419955814", "type": 0}]
[{"id": "624635532", "name": "624635532", "type": 0}, {"id": "1884595530", "name": "1884595530", "type": 1}]
[{"id": "791712670", "name": "791712670", "type": 0}]
[{"id": "895207852", "name": "895207852", "type": 0}]
[{"id": "144695994", "name": "144695994", "type": 0}, {"id": "384217055", "name": "384217055", "type": 0}]
[{"id": "1079725696", "name": "1079725696", "type": 0}]
J'ai une liste de valeurs pour id et je souhaite sélectionner n'importe quelle ligne contenant un objet avec l'une des valeurs de cette liste, dans le tableau du champ jsonb.
Est-ce possible? Y a-t-il un indice GIN que je peux faire pour accélérer cela?
Il n'y a pas d'opération unique, ce qui peut vous aider, mais vous avez quelques options:
1. Si vous avez un petit nombre (et fixe) d'ID à interroger, vous pouvez utiliser plusieurs opérateurs de confinement @>
Combinés avec or
; f.ex .:
where data @> '[{"id": "1884595530"}]' or data @> '[{"id": "791712670"}]'
Un simple index gin
peut vous aider sur votre colonne de données ici.
2. Si vous avez un nombre variable d'ID (ou si vous en avez beaucoup), vous pouvez utiliser json[b]_array_elements()
pour extraire chaque élément du tableau, créez une liste d'id, puis interrogez-la avec l'opérateur any-containment ?|
:
select *
from jsonbtest
where to_json(array(select jsonb_array_elements(data) ->> 'id'))::jsonb ?|
array['1884595530', '791712670'];
Malheureusement, vous ne pouvez pas indexer une expression contenant une sous-requête. Si vous souhaitez l'indexer, vous devez lui créer une fonction:
create function idlist_jsonb(jsonbtest)
returns jsonb
language sql
strict
immutable
as $func$
select to_json(array(select jsonb_array_elements($1.data) ->> 'id'))::jsonb
$func$;
create index on jsonbtest using gin (idlist_jsonb(jsonbtest));
Après cela, vous pouvez interroger des ID comme celui-ci:
select *, jsonbtest.idlist_jsonb
from jsonbtest
where jsonbtest.idlist_jsonb ?| array['193623800', '895207852'];
Remarque: J'ai utilisé notation par points/champ calculé ici, mais ce n'est pas obligatoire.
3. Mais à ce stade, vous n'avez pas à vous en tenir à json [b]: vous avez un simple tableau de texte, qui est pris en charge par PostgreSQL aussi.
create function idlist_array(jsonbtest)
returns text[]
language sql
strict
immutable
as $func$
select array(select jsonb_array_elements($1.data) ->> 'id')
$func$;
create index on jsonbtest using gin (idlist_array(jsonbtest));
Et interrogez ce champ calculé avec l'opérateur de tableau de chevauchement &&
:
select *, jsonbtest.idlist_array
from jsonbtest
where jsonbtest.idlist_array && array['193623800', '895207852'];
Remarque: D'après mes tests internes, cette dernière solution est calculée avec un coût plus élevé que la variante jsonb, mais en fait elle est plus rapide que cela, un peu. Si les performances comptent vraiment pour vous, vous devez tester les deux.
Je trouve une solution:where data::text similar to '%("id": "145119603"|"id": "1884595530")%'