PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Query LIKE sugli elementi dell'array jsonb piatto

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

Correlati, con spiegazione:

  • Cerca in un array JSON un oggetto contenente un valore che corrisponde a un pattern

O più semplice con il @? operatore poiché Postgres 12 ha implementato 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'operatore @? è solo un wrapper attorno alla funzione jsonb_path_exists() . Quindi questo è equivalente:

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

Nessuno dei due ha il supporto dell'indice. (Può essere aggiunto per @? operatore più tardi, ma non è ancora presente a pagina 13). Quindi quelle query sono lente per i tavoli grandi. Un design normalizzato, come già suggerito da Laurenz, sarebbe superiore, con un indice trigram:

  • Variazioni delle prestazioni delle query LIKE di PostgreSQL

Solo per corrispondenza dei prefissi (LIKE 'TAG%' , nessun carattere jolly iniziale), potresti farlo funzionare con un indice di testo completo :

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

E una query corrispondente:

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

Oppure usa l'english dizionario invece di simple (o qualunque cosa si adatti al tuo caso) se vuoi derivare per la lingua inglese naturale.

to_tsvector(json(b)) richiede Postgres 10 o successivo.

Correlati:

  • Ottieni una corrispondenza parziale dalla colonna TSVECTOR indicizzata GIN
  • Corrispondenza del modello con LIKE, SIMILAR TO o espressioni regolari in PostgreSQL