Dynamically fetch data with associations in simple query

Is it possible to dynamically fetch data using Ecto?

I found &Ecto.Query.API.map/2, but I can’t setup it properly for in dynamic single query.

Let’s say we have simple blog app.

With first example:

query = from p in Post,
  inner_join: a in assoc(p, :author),
  select: map(p, [:author_id, :title, author: [:first_name, :last_name]])
Repo.all(query)

I have list of maps with only :author_id and :title fields.

With second example:

query = from p in Post,
  inner_join: a in assoc(p, :author),
  select: map(p, [:title, :author_id, author: [:first_name, :last_name]])
Repo.all(query)

I received KeyError for :first_name (association not loaded).

Finally with third example:

query = from p in Post,
  preload: :author,
  select: map(p, [:title, :author_id, author: [:first_name, :last_name]])
Repo.all(query)

I received all info which I want, but not without any problems:

  1. Firstly I achieved it in 2 queries instead of 1.
  2. Secondly I was need to add extra field :author_id (as in documentation).

It’s not a big problem with writing such query manually, but I tried to find a way to fetch data dynamically. Can you help me with it?

yes its possible to dynamically fetch data but you have to build your query and then pass it inside the select if you want to fetch the data dynamically.like this:

fields =  fields ++ [{relation_name, Enum.map(value, &String.to_existing_atom/1)}]

here fields are the names of the the fields of the schema you want to select . relation_name is the preload table and Enum.map take fields of that preload table. then you can store this inside the variable and pass it inside select

         from q in queryable,
         select: map(q, ^Enum.uniq(fields))

The main point is to make your code generic for every possible select params.

@script: You got me wrong. I know how to pass variable to query etc.

In original post there are explained my 3 failures.
In my function I’m generating list like:

[:title, author: [:first_name, :last_name]]
# I'm generating everything without relation id.

I would like to dynamically create query with join (i.e. one SQL query) with parameters generated like in example (without relation id witch I do not need), but I could not get work join and select: map(…) together.