PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

LIKE requête sur les éléments du tableau plat jsonb

SELECT *
FROM   posts p
WHERE  EXISTS (
   SELECT FROM jsonb_array_elements_text(p.tags) tag
   WHERE  tag LIKE '%TAG%'
   );

Connexe, avec explication :

  • Rechercher dans un tableau JSON un objet contenant une valeur correspondant à un modèle

Ou plus simple avec le @? opérateur depuis Postgres 12 implémenté SQL/JSON :

SELECT *
--     optional to show the matching item:
--   , jsonb_path_query_first(tags, '$[*] ? (@ like_regex "^ tag" flag "i")')
FROM   posts
WHERE  tags @? '$[*] ? (@ like_regex "TAG")';

L'opérateur @? est juste un wrapper autour de la fonction jsonb_path_exists() . Donc c'est équivalent :

...
WHERE  jsonb_path_exists(tags, '$[*] ? (@ like_regex "TAG")');

Ni l'un ni l'autre n'a de support d'index. (Peut être ajouté pour le @? opérateur plus tard, mais pas encore à la page 13). Ces requêtes sont donc lentes pour les grandes tables. Une conception normalisée, comme Laurenz l'a déjà suggéré, serait supérieure - avec un index trigramme :

  • Variations des performances des requêtes PostgreSQL LIKE

Pour seulement la correspondance de préfixe (LIKE 'TAG%' , sans caractère générique de début), vous pouvez le faire fonctionner avec un index de texte intégral :

CREATE INDEX posts_tags_fts_gin_idx ON posts USING GIN (to_tsvector('simple', tags));

Et une requête correspondante :

SELECT *
FROM   posts p
WHERE  to_tsvector('simple', tags)  @@ 'TAG:*'::tsquery

Ou utilisez le english dictionnaire au lieu de simple (ou tout ce qui convient à votre cas) si vous voulez un stemming pour la langue anglaise naturelle.

to_tsvector(json(b)) nécessite Postgres 10 ou plus tard.

Connexe :

  • Obtenir une correspondance partielle à partir de la colonne TSVECTOR indexée GIN
  • Mise en correspondance de modèles avec LIKE, SIMILAR TO ou des expressions régulières dans PostgreSQL