Экто-запрос "влево-вправо" с использованием фрагмента

Я хотел бы запросить поле 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"])
Другие вопросы по тегам