If you want to improve something other than id , you can swap get_by with get as follows:
model = %User{email: " existing_or_new_email@heisenberg.net ", name: "Cat", ...} model |> User.upsert_by(:email) # => {:found, %User{...}} || {:ok, %User{...}} defmodule App.User do alias App.{Repo, User} def upsert_by(%User{} = record_struct, selector) do case User |> Repo.get_by({selector, record_struct |> Map.get(selector)}) do nil -> %User{} # build new user struct user -> user # pass through existing user struct end |> User.changeset(record_struct |> Map.from_struct) |> Repo.insert_or_update end end
In case of unforeseen circumstances, you are looking for a flexible approach that works in different models and several selectors (for example, country + passport number), check out my hex EctoConditionals package!
source share