Экто-запрос "влево-вправо" с использованием фрагмента
Я хотел бы запросить поле jsonb с помощью оператора postgres IN (с библиотекой Ecto)
Этот код работает с простым оператором =:
from a in query, where: fragment("?->>'format' = ?", a.properties, "foo")
Но я не могу сделать ни одну из этих попыток работать:
from a in query, where: fragment("?->>'format' IN ?", a.properties, ["foo", "bar"])
from a in query, where: fragment("?->>'format' IN (?)", a.properties, ["foo", "bar"])
from a in query, where: fragment("?->>'format' IN ?", a.properties, "('foo', 'bar')"])
Любая идея?
2 ответа
Решение
Помимо превосходного ответа Патрика, имейте в виду, что вы можете поместить только часть запроса во фрагмент. Например, вы можете переписать его так:
from a in query, where: fragment("?->>'format', a.properties) in ["foo", "bar"]
Если вы поместите фрагмент в макрос, вы даже можете получить читаемый синтаксис:
defmacro jsonb_get(left, right) do
quote do
fragment("?->>?", unquote(left), unquote(right))
end
end
И сейчас:
from a in query, where: jsonb_get(a.properties, "format") in ["foo", "bar"]
Это не имеет ничего общего с JSONB в частности. Ecto превратит ваш список типов в Postgres ARRAY
, который не работает с IN
оператор:
psql> SELECT 1 IN(ARRAY[1, 2, 3]);
ERROR: operator does not exist: integer = integer[]
Однако вы можете использовать = ANY()
проверить, содержится ли значение в ARRAY
:
psql> SELECT 1 = ANY(ARRAY[1, 2, 3]);
?column?
----------
t
(1 row)
Вы должны быть в состоянии использовать следующий фрагмент для достижения того же с Ecto:
fragment("?->>'format' = ANY(?)", u.properties, ["foo", "bar"])