2017-06-19 2 views
0

In einer meiner Phoenix-App-Tabellen habe ich ein Feld, das ein Array von Strings ist. Ich möchte in der Lage sein, einen where: like() Abfragetyp zu verwenden, um zu sehen, ob irgendwelche der Werte in dem Array eine Abfragezeichenfolge enthalten - jedoch bin ich nicht sicher, wie das zu tun ist. In einer früheren Iteration der App, war das betreffende Feld nur ein String-Feld, und die folgende Abfrage funktionierte perfekt:Phoenix/Ecto - Abfrage nach Übereinstimmungen im String-Array

results = from(u in User, 
    where: like(u.fulltext, ^("%#{search_string}%")) 
    |> Repo.all() 

Jetzt, wo ich das fulltext Feld in ein Array von Strings geändert habe (character varying(255)[], in Postgres Begriffe), diese Abfrage fehlschlägt verständlicherweise mit dem Fehler

ERROR 42883 (undefined_function): operator does not exist: character varying[] ~~ unknown 

aber ich bin nicht sicher, wie ich die Abfrage verfeinern könnte das neue Schema entsprechen.

Zum Beispiel eines fulltext Feld des Benutzers wird wie folgt aussehen

["john smith", "[email protected]"] 

und die dazugehörige Datensatz zurückgegeben werden soll, wenn search_string"john" oder "@test" oder "n smith" ist usw. - wenn die search_string einen Teil entweder der Spiele Listenwerte.

In einfachem Englisch würde die Abfrage etwas wie "record records lesen, wo ein Wert wie search_string in der Liste u.fulltext gefunden wird".

ich von verschiedenen ‚Hacky‘ Abhilfen denken kann, wie einfach die Liste aller Benutzer zurückkehren und dann einige gekettet Enum.map Funktionen durch sie laufen und die Werte von fulltext für teilweise Übereinstimmungen zu überprüfen, aber wenn es eine elegantere Lösung Mit Ectos Abfragesyntax würde ich mich lieber dafür entscheiden. Kann mir irgendjemand eine Anleitung anbieten?

Antwort

2

Sie unnest in PostgreSQL mit einer Unterabfrage verwenden können, um zu überprüfen, ob jedes Element eines Arrays ist LIKE something:

from(p in Post, select: p.tags, where: fragment("exists (select * from unnest(?) tag where tag like ?)", p.tags, "%o%") 

In Ihrem Fall das funktionieren soll:

from(u in User, where: fragment("exists (select * from unnest(?) tag where tag like ?)", u.fulltext, ^("%#{search_string}%")) 
iex(1)> Repo.insert! %Post{tags: ~w(foo bar baz)}                    [debug] QUERY OK db=0.3ms 
iex(2)> Repo.insert! %Post{tags: ~w(quux)} 
iex(3)> Repo.insert! %Post{tags: ~w(hello world)} 
iex(4)> query = "%o%" 
"%o%" 
iex(5)> Repo.all from(p in Post, select: p.tags, where: fragment("exists (select * from unnest(?) tag where tag like ?)", p.tags, "%o%")) 
[debug] QUERY OK source="posts" db=3.9ms 
SELECT p0."tags" FROM "posts" AS p0 WHERE (exists (select * from unnest(p0."tags") tag where tag like '%o%')) [] 
[["foo", "bar", "baz"], ["hello", "world"]] 
1

Sie können fragment und unnest verwenden, um das Array in einen Join zu konvertieren:

user_texts = 
    from u in User, 
    select: %{id: u.id, fulltext: fragment("unnest(fulltext)")} 

query = 
    from u in User, 
    join: t in subquery(user_texts), on: u.id == t.id, 
    where: like(t.fulltext, ^("%#{search_string}%")), 
    select: u, 
    distinct: true 

Repo.all(query) 
Verwandte Themen