使用片段Ecto"左右IN"查询

Chr*_*ris 3 elixir ecto phoenix-framework

我想使用postgres IN运算符(使用Ecto库)查询jsonb字段

此代码使用simple =运算符:

from a in query, where: fragment("?->>'format' = ?", a.properties, "foo")
Run Code Online (Sandbox Code Playgroud)

但我无法做出任何这些尝试:

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')"])
Run Code Online (Sandbox Code Playgroud)

任何的想法?

Jos*_*lim 7

除了Patrick的出色响应之外,请记住,您也只能将部分查询放入片段中.例如,您可以将其重写为:

from a in query, where: fragment("?->>'format', a.properties) in ["foo", "bar"]
Run Code Online (Sandbox Code Playgroud)

如果您将片段放在宏中,您甚至可以获得可读的语法:

defmacro jsonb_get(left, right) do
  quote do
    fragment("?->>?", unquote(left), unquote(right))
  end
end
Run Code Online (Sandbox Code Playgroud)

现在:

from a in query, where: jsonb_get(a.properties, "format") in ["foo", "bar"]
Run Code Online (Sandbox Code Playgroud)


Pat*_*ity 6

这与JSONB无关.Ecto会将您的类型列表转换为PostgresARRAY,但不适用于IN运营商:

psql> SELECT 1 IN(ARRAY[1, 2, 3]);
ERROR:  operator does not exist: integer = integer[]
Run Code Online (Sandbox Code Playgroud)

但是,您可以使用= ANY()以检查值是否包含在ARRAY:

psql> SELECT 1 = ANY(ARRAY[1, 2, 3]);
 ?column?
----------
 t
(1 row)
Run Code Online (Sandbox Code Playgroud)

您应该能够使用以下片段来实现与Ecto相同的功能:

fragment("?->>'format' = ANY(?)", u.properties, ["foo", "bar"])
Run Code Online (Sandbox Code Playgroud)