Repository navigation
Ecto upsert for partial data updates
I have a record that I want to insert or update specific fields on that record if it exists already.
How do I write an Ecto
Repo.insertstatement to handle this?
Handling upserts is easy with Ecto. Repo.insert takes a :on_conflict option that performs a PostgreSQL upsert.
For example, if you had a User record that can be signed in via social platforms, you can simply try to insert the user based on whatever attributes we get from the social platform.
We key on the email since that should always be unique. If the email is found, then we'll perform and update to set only the uid we got from the social platform.
%User{}
|> User.create_social_changeset(attributes)
|> Repo.insert(
conflict_target: {:unsafe_fragment, "(lower(email))"},
on_conflict: {:replace, [:social_uid]},
returning: true
)When handling partial updates we want to include returning: true to make sure we refetch data that we didn't update as it is likely not what is in the struct; e.g. we autogenerate a unique token for session login, we want to make sure to refetch to get the token that was not updated so login continues to work.
🏳️🌈🦄 Sharing is caring. 🦄🏳️🌈
TODO: can we recreate the tag system here roughly with sections about certain subjects?