Ecto "left IN right" 使用片段查询

Ecto "left IN right" query using a fragment

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

此代码使用简单的 = 运算符:

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')"])

有什么想法吗?

这与 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"])

除了 Patrick 的出色响应之外,请记住,您也可以只将查询的一部分放入片段中。比如你可以改写为:

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"]