【问题标题】:Phoenix/Ecto - query for matches in array of stringsPhoenix/Ecto - 查询字符串数组中的匹配项
【发布时间】:2017-06-19 11:05:23
【问题描述】:

在我的 Phoenix 应用程序的一个表中,我有一个字段是字符串数组。我希望能够使用 where: like() 类型的查询来查看数组中的任何值是否包含查询字符串 - 但是,我不知道该怎么做。在应用程序的先前迭代中,有问题的字段只是一个字符串字段,以下查询完美运行:

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", "john@test.com"]

search_string"john""@test""n smith" 等时,应返回相关记录 - 如果search_string 匹配任一列表值的任何部分。

在简单的英语中,查询将读取类似“返回在列表u.fulltext 中找到类似search_string 的值的记录”。

我可以想到各种“hacky”解决方法,比如只返回所有用户的列表,然后使用一些链接的 Enum.map 函数来运行它们并检查 fulltext 的值是否部分匹配,但如果有使用 Ecto 的查询语法的更优雅的解决方案,我宁愿选择它。任何人都可以提供任何指导吗?

【问题讨论】:

    标签: postgresql elixir phoenix-framework ecto


    【解决方案1】:

    您可以在 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"]]
    

    【讨论】:

      【解决方案2】:

      您可以使用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)
      

      【讨论】:

      • 嘿,如果 fulltax 是一系列地图,您能否添加示例?
      • @DokiCRO 您能否以架构示例的形式提出一个新问题?
      猜你喜欢
      • 2021-12-26
      • 2018-05-23
      • 2012-12-09
      • 2014-07-21
      • 2020-08-07
      • 1970-01-01
      • 1970-01-01
      • 2021-12-17
      • 1970-01-01
      相关资源
      最近更新 更多