PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

LIKE-Abfrage für Elemente eines flachen jsonb-Arrays

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

Verwandte, mit Erklärung:

  • Durchsuchen Sie ein JSON-Array nach einem Objekt, das einen Wert enthält, der einem Muster entspricht

Oder einfacher mit dem @? Operator seit Postgres 12 SQL/JSON implementiert:

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

Der Operator @? ist nur ein Wrapper um die Funktion jsonb_path_exists() . Das ist also äquivalent:

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

Keiner hat Indexunterstützung. (Kann für @? hinzugefügt werden Operator später, aber noch nicht auf Seite 13). Daher sind diese Abfragen für große Tabellen langsam. Besser wäre ein normalisiertes Design, wie Laurenz es bereits vorgeschlagen hat - mit einem Trigram-Index:

  • Änderungen der PostgreSQL LIKE-Abfrageleistung

Nur für den Präfixabgleich (LIKE 'TAG%' , kein führender Platzhalter), könnten Sie es mit einem Volltextindex zum Laufen bringen :

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

Und eine passende Abfrage:

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

Oder verwenden Sie das english Wörterbuch statt simple (oder was auch immer zu Ihrem Fall passt), wenn Sie die Wortstammbildung für die natürliche englische Sprache wünschen.

to_tsvector(json(b)) erfordert Postgres 10 oder später.

Verwandte:

  • Teilweise Übereinstimmung aus GIN-indizierter TSVECTOR-Spalte abrufen
  • Mustervergleich mit LIKE, SIMILAR TO oder regulären Ausdrücken in PostgreSQL