Caching database values (or storing them to an elixir module on application start) to reduce database calls for static values

I have a User model defined with:

belongs_to :institute, Mango.Institutes.Institute
field :prefix, :string, virtual: true

And an Institute model defined with:

field :prefix, :string

When using the application I need to have the prefix filed value for the institute the user belongs to.

What I have done so far to do that is this, inside Accounts context (the User context):

  # mofified to load user institute's prefix
  def get(id) do 
    Repo.get(User, id)
    |> case do u -> Map.put(u, :prefix, get_institutes_prefix(u.institute_id)) end

  def get_institutes_prefix(id) do 
    Repo.get(Mango.Institutes.Institute, id).prefix

Works fine, but this means that the database is called twice, once to get the user and once to get institutes prefix value.

My question, how to optimize all of this? Is it possible to generate once in a while (in code) (or upon creating new institutes) some .ex file with all those institute_id - prefix key value pairs and retrieve the prefix value for users in code without querying the database?

Thank you.

You could do the following to directly grab the prefix of the institute a given user belongs to and embed it into the user’s object, all from a single query.

defmodule Test.Something do
  import Ecto.Query

  alias Test.Repo
  alias Test.User

  def get_user(id) do \
    from u in User,
      where: == ^id,
      join: i in assoc(u, :institute),
      select: %{u | prefix: i.prefix}

If you are doing this from a Phoenix context, you might not have to import Phoenix.Query nor include an alias for your Repo because those may already be present. Have a read on Ecto’s join and select macros for reference.

1 Like

Thank you @satom99, I guess using join is the best. I was thinking about some memory storage for those prefixes, but a simple join like this one will not suffer any performance issues no matter how many users are connected, I guess.