Getting a value which isn't nil in Ecto

I have this model:

  schema "my_model" do
    field :name, :string

    belongs_to :model1, Model1
    belongs_to :model2, Model2
    belongs_to :model3, Model3
    belongs_to :model4, Model4

Only one of these foreign fields can have a value at a time. How can I get one with a value? Is this a good approach?

  def get_current_fr_model(my_model) do
    my_model.model1 || my_model.model2 || my_model.model3 || my_model.model4

or is there a better way?

If you already have access to my_model, then I’d probably check for the existence of the foreign key first, i.e., my_model.model1_id before I actually try to query for each model—that could save you 3 database calls

Otherwise, you could try left outer joins (using Ecto.Query.join/5) on Model1, Model2, Model3 and Model4, add a “where IS NOT NULL” type clause and then add a LIMIT 1. That’s very likely overkill, and might not even be the most performant option, as left outer joins aren’t always the fastest route. You could build structs from your query (using Ecto.Query.API.struct/2) and then something like your get_current_fr_model might be a reasonable solution. All of that would make it doable in a single database call.

As far as the logic of get_current_fr_model goes, I think I personally would prefer throwing the models into a list and using Enum.find/3 over a bunch of || operators.


I don’t have an answer if this is a good approach but I have an idea about the “is there a better way?”

My assumption is that you want a model to be able to be related to various models. For example a “comment” can be made about a “bug” or a “feature request” or whatever but not about both. In this case you would be better if you used intersection tables. The idea is you have three models. “post”, “comments” and “feature_requests”. You create an intersection table “post_comments” that points to both posts and comments and query that. Same for feature requests.

The free ecto book from plataformatec describes how to do that with ecto. It call’s it “Polymorphic associations”

I hope this is what you are looking after.

For me, it feels clearer what the intent is: from this list of models, pick the one that is present.

But as with everything in programming, it comes down to personal preference, and if there is a performance hit for either method, I doubt it would be the bottleneck.