2016-12-06 5 views
1

나는 모델을 가지고 :Ecto + Elixir : 어떻게 해시 맵 필드를 쿼리합니까?

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을 사용하여 수행 할 수 있습니다.

열이 foobar"baz"에 값이 포함 된 경우 쿼리 foo.bar ? 'baz'가 체크하는 SQL. 이것은 다음과 같이 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