2017-06-19 52 views
0

在我的Phoenix應用程序的一個表中,我有一個字符串數組。我希望能夠使用where: like()類型的查詢來查看數組中的任何值是否包含查詢字符串 - 但是,我不確定如何執行此操作。在應用程序中的前一次迭代,有問題的領域只是一個字符串字段,以及下面的查詢工作完美:Phoenix/Ecto - 查詢字符串數組中的匹配項

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

現在,我已經改變了fulltext場到字符串數組(character varying(255)[],Postgres裏計),這個查詢理解失敗,出現錯誤

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

,但我不知道我怎麼會細化查詢相匹配的新的模式。

例如,用戶的fulltext領域會像

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

search_string"john""@test""n smith"等應退還相關記錄 - 如果search_string任的任何部分匹配列表值。

用普通英語,查詢會讀取類似於「返回記錄,其中在列表u.fulltext中找到類似search_string的值」。

我能想到的各種「哈克」的解決方法,就像剛返回的所有用戶的列表,然後使用一些鏈接Enum.map功能,通過它們來運行,並檢查fulltext值部分匹配,但如果有一個更優雅的解決方案使用Ecto的查詢語法,我寧願選擇它。任何人都可以提供指導嗎?

回答

2

你可以在PostgreSQL使用unnest使用子查詢檢查數組的任何產品LIKE something

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

在你的情況,這應該工作:

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

您可以使用fragmentunnest將數組轉換爲連接:

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)