2016-12-06 2 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 поля сохраняются в виде JSONB полей в PostgreSQL по Ecto. Ecto не предоставляет никаких функций для выполнения определенных операций над такими полями, но это можно сделать с помощью fragment и пользовательского SQL.

SQL-запрос foo.bar ? 'baz' проверит, если столбец bar из foo содержит значение ключа "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

Смежные вопросы