2017-06-19 36 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)