coen.bakker

coen.bakker

How to add fields of associated schema to fields of parent schema when querying with Ecto?

Context
I have several different types of books that are stored in my database. All books have some properties in common, but all book types have their own unique properties as well. Currently, I have a schema for the shared properties of books (books) and one for the non-shared properties of each type of book (type_a_books, type_b_books, etc).

  schema "books" do
    field :title, :string
    ...
    field :type, :string # "TypeABook", "TypeBBook", etc.

    has_many :publications, Publication
    many_to_many :authors, Author, join_through: "authors_books"

    has_one :type_a_book, TypeABook
    has_one :type_b_book, TypeBBook

    timestamps()
  end
  schema "type_a_books" do
    field :story, :string
    field :pictures, {:array, :string}
    belongs_to :book, Book
  end
  schema "type_b_books" do
    field :paths, {:array, :string}
    field :pictures, {:array, :string}
    field :videos, {:array, :string}
    belongs_to :book, Book
  end

I setup this model recently but I am now faced with the fact that I do not have a sufficient understanding of how to perform the needed queries. I have read the documentation of Ecto.Query, Ecto.Repo and Ecto.Schema, and learnt from several other sources.

Problem
I have not been able to figure out how to get the following data back from the database (N.B. the fields of TypeABook are joined to the fields of Book).

%{
  id: "qwerty",
  title: "A Purple Sky over Tokyo",
  ...
  type: "type_a_book",
  publications: [ #App.Publications.Publication<...> ],
  authors: [ #App.Authors.Author<...> ],
  story: "hello",
  pictures: ["url", "url", "url"],
  inserted_at: ~U[2023-02-20 13:06:54Z],
  updated_at: ~U[2023-02-20 13:06:54Z]
}

The closest I got to this result is a simple query = from d in Draft, preload: [:authors, :publications, :type_a_book]. This, however, does not add the fields of TypeABook to the fields of Book. I have also tried to use join in assoc() and join in TypeABook, but I could never get it to work fully.

Feel free to also comment on my model or the general approach I am taking.

Most Liked

milangupta

milangupta

Here is one approach that might work ?

And a previous forum post/pointer from @LostKobrakai - Data mapping and validation — Ecto v3.14.0

LostKobrakai

LostKobrakai

If your read and write side look rather different you can also go with different schemas fror them. Noone requires you do use the same ones.

milangupta

milangupta

Glad it was helpful. It is a learning journey. I’m on my 3rd refactoring / re-design. What I love about the stack is that it is easy for a newbie to create something and then as you learn, you can really create some elegant stuff.

Your choices will really depend on the complexity of your application. There is still more to do with Ecto, but for simple/medium complexity stuff, it is great ! An example where I am still learning .. in designing the model with assocs (has_many/belongs_to etc.), the stuff that I still have to test thoroughly is around when a record is deleted (and the behavior of cascading deletes), specifically when a value is NULL. Postgres15’s addition of NULL not unique was a very very needed enhancement that was previously causing me a lot of workarounds etc.

Hope this helps ..

Where Next?

Popular in Questions Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; somethi...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lists...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
LegitStack
I’m trying to make a websocket server in Phoenix or raw Elixir. I heard about gun, I think I could use cowboy, but since I’m not that sma...
New
Lily
In templates/appointment/index.html.eex: &lt;%= for appointment &lt;- @appointments do %&gt; &lt;tr&gt; &lt;td&gt;&lt;%= appoi...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New

Other popular topics Top

hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a &gt; b) do {:ok, "a"} end if (a &lt; b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43806 214
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
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
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" =&gt; #BSON.ObjectId&lt;58eb1a7a9ad169198c3dXXXX&gt;, "email" =&gt; ...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement