trisolaran

trisolaran

Foreign key in jsonb field for ecto association

Hello :wave:,

I’m trying to define a one-to-many association where the child’s foreign key is contained inside a jsonb field.
I have a parent table (let’s just call it parent) with an integer primary key field id.
I have a child table called child with ecto schema Child and a field args of type jsonb.
The field args is a json object with the following structrure:

{
  parent_id, <- this points to the primary key of "parent"
  ...
  <other_fields>
}

I would like to define a has_many association on the parent’s schema, something along these lines:

schema "parent" do 

  has_many :children, Child, foreign_key: fragment("(args->>'parent_id')::int")
end

I’m aware that this won’t work in Ecto, but it will hopefully convey what I’m trying to achieve.

I’m also aware that I could change the child’s table’s schema to add an ordinary foreign key, but it’s something I would like to avoid because the table and its schema are managed by an external library. Also, I don’t want to clutter the table with ad-hoc keys for this specific use case, as the same table will be used in other scenarios.

My workaround would have been to manage the children field myself without Ecto. That would of course work.

However, before I go down that path, I wanted to ask if there is a way to achieve this directly with Ecto. I suspect that this is not possible, but perhaps someone here has some suggestions on how to “trick” Ecto into recognizing this kind of association.

Thank you very much in advance!

Marked As Solved

trisolaran

trisolaran

Thanks for your answer and yeah, excited to be here :slight_smile:

As I mentioned, I know that I could add perent_id to Child, but I don’t want to do it because I don’t manage the child table or its schema. The child table is a general purpose table managed by a different library.

I can’t change the Child schema either, for the very same reason.

That said, if I could change the Child schema, your suggestion of “giving shape” to the jsonb field via an embedded schema would be an interesting one.
However, I doubt that it would work, because the foreign_key option in the has_many definition in the parent table requires a top-level field in the child schema. How would I pass a field in an embedded schema to it?

I thought about this a bit more yesterday and I believe that a decent way to solve this in Ecto is to use a has_many through association (the Child table does have primary keys). So I could create a parent_child join table with following schema:

defmodule ParentChild do

  schema "parent_child" do 
     belongs_to :parent, Parent
     belongs_to :child, Child
  end
end

and then:

defmodule Parent do
  schema "parent" do 
    has_many :parent_child, ParentChild

    has_many :children, Child, through: [:parent_child, :child] 
  end
end

That would solve the problem I believe, albeit at the cost of one additional table. I will take this idea for a spin soon.

Where Next?

Popular in Questions Top

Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
LegitStack
I’m hoping you guys can give me some general advice and perhaps code examples if you’re feeling up to it. I’m very interested in Elixir,...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
makeitrein
Hey all, just started picking up Elixir last week and am writing a scraper as a learning project. Baby step #1 is extracting the number ...
New
Exadra37
Sometimes I want to check if the input into a function is not a blank string. My first approach: defmodule Example do def do_stuff(s...
New
hpopp
To simplify some tasks at work, I wrote and published this package yesterday. It’s a simple macro that enables Access behaviour on struct...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New

Other popular topics Top

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
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
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 record...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
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
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

We're in Beta

About us Mission Statement