imprest

imprest

How to get json result as raw binary from Postgres Query

I would like the resulting json from Postgrex query; to not be decoded by Jason.

Instead let it return as a binary / string and sent straight as a response; to avoid the decoding from db and then encoding when sending to client.

  • Below code does not work. Currently sending it by using

Jason.encode!(List.flatten(result.rows))"

query = "select array_to_json(array_agg(customers)) from customers"
{:ok, result} = Ecto.Adapters.SQL.query(Repo, query, [])

conn
|> put_resp_content_type("application/json")
|> send_resp(200, List.flatten(hd(result.rows)))

Marked As Solved

michalmuskala

michalmuskala

If you’re using jason, you can use Jason.Fragment.new(iodata) which was designed especially for that use case. The docs are… a bit lacking :sweat_smile:.

This basically implements exactly what I described in my blog post about doing something similar in Poison.

Also Liked

imprest

imprest

Taking @michalmuskala, @sribe and @hauleth advise and
looking around the inter-webs; came up with the below examples.
Hope it helps others.

# customer_controller.ex
def index(conn, _params) do
  query = "SELECT json_agg(customers)::text FROM customers"
  result = Repo.query!(query, [])

  conn
  |> put_resp_content_type("application/json")
  |> send_resp(200, ["{\"list\":", result.rows, "}"])
end

More complex example; return an invoice as json object with customer details and list of items bought

# invoice_controller.ex
def show(conn, %{"id" => id}) do
  query = """
  SELECT row_to_json(invoice)::text
  FROM (
    SELECT *,
    (
      SELECT row_to_json(c)
      FROM (
        SELECT *
        FROM customers
        WHERE invoices.customer_id = customers.id
      ) c
    ) AS customer,
    (
      SELECT json_agg(i)
      FROM (
        SELECT id, product_id, qty, rate, total
        FROM invoice_details
        WHERE invoice_id = $1::bigint
      ) i
    ) AS items
    FROM invoices
    WHERE id = $1::bigint
  ) invoice;
  """

  result = Repo.query!(query, [id])

  conn
  |> put_resp_content_type("application/json")
  |> send_resp(200, ["{\"data\":", result.rows, "}"])
end
michalmuskala

michalmuskala

Also, you don’t need the List.flatten(hd(result.rows)) part. The body passed to send_resp can be iodata, which, among others, means a nested list of binaries. send_resp(200, result.rows) should work just fine.

Also using SELECT json_agg(customers)::text FROM customers might improve things on the DB side.

hauleth

hauleth

Have you tried casting in the DB? Like:

query = "select array_to_json(array_agg(customers))::text from customers"
{:ok, result} = Repo.query(query, [])

conn
|> put_resp_content_type("application/json")
|> send_resp(200, List.flatten(hd(result.rows)))

Last Post!

sribe

sribe

Yes. My hack is not a lot of code, nor complicated, but it hardwires an assumption of JSON into Phoenix at an inappropriate place. Jason.Fragment.xxx is an appropriate API for decoupling that so that encoders for other formats could be hooked in.

Where Next?

Popular in Questions Top

nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New

Other popular topics Top

baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New

We're in Beta

About us Mission Statement