2016-12-06 52 views
1

我有一個模型:Ecto + Elixir:我如何查詢hashmap字段?

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

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

    timestamps() 
    end 

    ... 
end 

我怎麼會找所有用戶在他們的matches哈希一個「爽」鍵?

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

回答

3

:map字段被存儲爲的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') [] 
[] 
+0

哇...你又救了我一次 – Edmund