Ecto “left IN right” query using a fragment

纵饮孤独 提交于 2019-12-10 17:46:47

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!