denis
Ecto fragment jsonb[] interpolation
Hi, I’m running into problems when trying to interpolate somewhat “simple” json query using a fragment.
I have a jsonb column in postgres that has the following structure (array of objects):
[{"name": "test", ...}, {"name": "another", ...}, ...]
Let’s start with the SQL query that gets me what I need:
SELECT count(*)
FROM "posts" AS p0
WHERE (p0."jsonb_column" @> ANY( ARRAY [ '[{"name": "test"}]', '[{"name": "another"}]' ]::jsonb[]));
Translated to ecto (without parametrised variables) this works just fine:
from(p in Post,
where:
fragment(
"? @> ANY (ARRAY['[{\"name\":\"test\"}]','[{\"name\": \"another\"}]']::jsonb[])",
p.jsonb_column
)
)
|> Repo.aggregate(:count)
However when I use parametrised values it ends up generating a slightly different sql query, which obviously doesn’t return the same results. This is the closest I can get it:
vals = [[%{"name" => "test"}], [%{"name" => "another"}]]
from(
p in Post,
where:
fragment(
"? @> ANY (ARRAY [?]::jsonb[])",
p.jsonb_column,
^vals
)
)
|> Repo.aggregate(:count)
This generates the following SQL:
SELECT count(*) FROM "posts" AS p0 WHERE (p0."jsonb_column" @> ANY (ARRAY [$1]::jsonb[]))
with parameters: $1 = '[[{"name": "test"}], [{"name": "another"}]]'
correct parameters would be: '[{"name": "test"}]', '[{"name": "another"}]'
Any ideas about how can I get this to work? Cheers!
First Post!
al2o3cr
I don’t think ARRAY is going to do what you want - ARRAY[$1] means an array with exactly one element taken from the bind parameters.
What might work better is passing the list serialized as a SQL array of JSON:
$1 = '{"{\"name\": \"test\"}", "{\"name\": \"another\"}"}'
Then the consuming code looks like ? @> ANY(?::jsonb[])
You may need to supply additional type information for vals to make this work.
Last Post!
denis
Thanks @al2o3cr, I tried this approach too by serializing values individually within a list, however it still doesn’t produce the correct results. Not sure if I’m doing it correctly though…
vals = [[%{"name" => "test"}], [%{"name" => "another"}]]
serialized = vals |> Enum.map(fn x -> x |> Jason.encode!() end)
with fragment being:
fragment("? @> ANY(?::jsonb[])",
p.services,
^serialized
)
I don’t think this is necessary, because the raw sql query works as expected without it, it’s just I can’t get ecto to do the same thing ![]()
Popular in Announcing
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex









