在我的一个凤凰应用程序表中,我有一个字符串数组的字段。我希望能够使用OpenCSVSerde
类型的查询来查看数组中的任何值是否包含查询字符串 - 但是,我不知道如何做到这一点。在应用程序的上一次迭代中,有问题的字段只是一个字符串字段,以下查询完美地运行:
where: like()
现在我已将results = from(u in User,
where: like(u.fulltext, ^("%#{search_string}%"))
|> Repo.all()
字段更改为字符串数组(fulltext
,在Postgres术语中),此查询可以理解为失败并显示错误
character varying(255)[]
但我不确定如何优化查询以匹配新架构。
例如,用户的ERROR 42883 (undefined_function): operator does not exist: character varying[] ~~ unknown
字段将显示为
fulltext
并且["john smith", "john@test.com"]
为search_string
或"john"
或"@test"
等时应返回相关记录 - 如果"n smith"
与任何一方相匹配列表值。
简单来说,查询会读取类似“返回记录,其中search_string
列表中的值search_string
”。
我可以想到各种“hacky”解决方法,比如只返回所有用户的列表,然后使用一些链式u.fulltext
函数来运行它们并检查Enum.map
的值以进行部分匹配,但如果使用Ecto的查询语法有一个更优雅的解决方案,我宁愿选择它。任何人都可以提供任何指导吗?
答案 0 :(得分: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 :(得分:2)
您可以使用fragment
和unnest
将数组转换为连接:
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)