问题
I would like to query a jsonb field using postgres IN operator (with Ecto library)
This code work with a simple = operator:
from a in query, where: fragment("?->>'format' = ?", a.properties, "foo")
But I cannot make any of these attempts to work:
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')"])
Any idea?
回答1:
Besides Patrick's excellent response, keep in mind you can put only part of a query in a fragment too. For example, you can rewrite it to:
from a in query, where: fragment("?->>'format', a.properties) in ["foo", "bar"]
If you put the fragment in a macro, you can even get a readable syntax:
defmacro jsonb_get(left, right) do
quote do
fragment("?->>?", unquote(left), unquote(right))
end
end
And now:
from a in query, where: jsonb_get(a.properties, "format") in ["foo", "bar"]
回答2:
This has nothing to do with JSONB in particular. Ecto will turn your list of types into a Postgres ARRAY, which does not work with the IN
operator:
psql> SELECT 1 IN(ARRAY[1, 2, 3]);
ERROR: operator does not exist: integer = integer[]
However you can use = ANY() to check if the value is contained in an ARRAY
:
psql> SELECT 1 = ANY(ARRAY[1, 2, 3]);
?column?
----------
t
(1 row)
You should be able to use the following fragment to achieve the same with Ecto:
fragment("?->>'format' = ANY(?)", u.properties, ["foo", "bar"])
来源:https://stackoverflow.com/questions/34660486/ecto-left-in-right-query-using-a-fragment