elixir - 埃克托+ Elixir : How do I query a hashmap field?

标签 elixir phoenix-framework ecto

我有一个模型:

defmodule VideoChat.User do
  use VideoChat.Web, :model

  schema "users" do
    field :device_identifier, :string
    field :matches, :map

    timestamps()
  end

  ...
end

我如何查找 matches 哈希中具有“cool”键的所有用户?

User |> where([u], u.matches["cool"] != nil) |> limit(1) |> VideoChat.Repo.one

最佳答案

:map 字段由 Ecto 在 PostgreSQL 中存储为 JSONB 字段。 Ecto 不提供任何函数来对此类字段执行映射特定操作,但可以使用 fragment 和自定义 SQL 来完成。

SQL 查询 foo.bar ? 'baz' 将检查 foobar 列是否包含键 "baz" 中的值。这可以用fragment来表达,如下所示:

fragment("? \\? ?", foo.bar, "baz")

所以你的代码应该修改为:

User |> where([u], fragment("? \\? ?", u.matches, "cool")) |> limit(1) |> VideoChat.Repo.one

在全新的 Map 模型中,键 map 类型为 :map:

iex(1)> Repo.insert! %MyApp.Map{map: %{}}
iex(2)> Repo.insert! %MyApp.Map{map: %{foo: 1}}
iex(3)> Repo.insert! %MyApp.Map{map: %{foo: 2}}
iex(4)> Repo.insert! %MyApp.Map{map: %{bar: 1}}
iex(5)> Repo.all MyApp.Map |> where([m], fragment("? \\? ?", m.map, "foo"))
[debug] QUERY OK source="maps" db=1.8ms decode=5.3ms
SELECT m0."id", m0."map", m0."inserted_at", m0."updated_at" FROM "maps" AS m0 WHERE (m0."map" ? 'foo') []
[%MyApp.Map{__meta__: #Ecto.Schema.Metadata<:loaded, "maps">, id: 2,
  inserted_at: #Ecto.DateTime<2016-12-07 10:19:53>, map: %{"foo" => 1},
  updated_at: #Ecto.DateTime<2016-12-07 10:19:53>},
 %MyApp.Map{__meta__: #Ecto.Schema.Metadata<:loaded, "maps">, id: 3,
  inserted_at: #Ecto.DateTime<2016-12-07 10:19:55>, map: %{"foo" => 2},
  updated_at: #Ecto.DateTime<2016-12-07 10:19:55>}]
iex(6)> Repo.all MyApp.Map |> where([m], fragment("? \\? ?", m.map, "bar"))
[debug] QUERY OK source="maps" db=2.9ms queue=0.2ms
SELECT m0."id", m0."map", m0."inserted_at", m0."updated_at" FROM "maps" AS m0 WHERE (m0."map" ? 'bar') []
[%MyApp.Map{__meta__: #Ecto.Schema.Metadata<:loaded, "maps">, id: 4,
  inserted_at: #Ecto.DateTime<2016-12-07 10:19:59>, map: %{"bar" => 1},
  updated_at: #Ecto.DateTime<2016-12-07 10:19:59>}]
iex(7)> Repo.all MyApp.Map |> where([m], fragment("? \\? ?", m.map, "baz"))
[debug] QUERY OK source="maps" db=2.2ms queue=0.1ms
SELECT m0."id", m0."map", m0."inserted_at", m0."updated_at" FROM "maps" AS m0 WHERE (m0."map" ? 'baz') []
[]

关于elixir - 埃克托+ Elixir : How do I query a hashmap field?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41006696/

相关文章:

pattern-matching - 使用什么数据结构来实现模式匹配?

compiler-errors - 警告 : Ecto. Repo.insert_all/3 未定义或私有(private)

elixir - 为什么我不能在 Elixir 闭包函数头中使用 pin 运算符?

oauth - Elixir Phoenix 设置和使用环境变量

phoenix-framework - 如何让 Phoenix LiveView 更新?

javascript - "[object Object]"协议(protocol)枚举未实现

testing - 在测试中访问参数

elixir - `virtual: true` 对嵌入式架构有影响吗?

elixir - 在 Elixir 中传递并使用命名函数?

html - 如何在链接助手中插入分配?