What is the simplest way to do upsert with Ecto (MySQL)

Teo Choong Ping picture Teo Choong Ping · Jun 8, 2016 · Viewed 8.5k times · Source

Doing upsert is common in my app and I want to implement the cleanest and simple way to implement upsert.

  1. Should I use fragments to implement native sql upsert?
  2. Any idiomatic ecto way to do upsert?

Answer

Alex Troush picture Alex Troush · Jun 8, 2016

You can use Ecto.Repo.insert_or_update/2, please note that for this to work, you will have to load existing models from the database.

 model = %Post{id: 'existing_id', ...}
 MyRepo.insert_or_update changeset
 # => {:error, "id already exists"}

Example:

result =
  case MyRepo.get(Post, id) do
    nil  -> %Post{id: id} # Post not found, we build one
    post -> post          # Post exists, let's use it
  end
  |> Post.changeset(changes)
  |> MyRepo.insert_or_update

case result do
  {:ok, model}        -> # Inserted or updated with success
  {:error, changeset} -> # Something went wrong
end