How to update field if changed using Ecto

Tags: #<Tag:0x00007fcf980866e0> #<Tag:0x00007fcf980865a0>


Hi folks,
I’m working with football data in Mix project. My API does not support event system :frowning:. Way that I take data is time based (cron like). So far every record in Postgres tables have hash field based on data hash. If my hash is different than I go to update, else do nothing.
What is best way to do this logic? I’m thinking in model to create function that contains this logic (upsert_by_…), get record (by uniq id non AI) if exists, perform calculations and execute insert/update/nothing.
I’m working with hash to eliminate multi value comparison.


It’s not a popular theme, let me show you some example:

defmodule Api.Upsert do

  alias Api.Repo

  defmacro __using__(_) do
    quote do
      def upsert(data) do
        record = Repo.get_by(__MODULE__, api_id: data.api_id)
        save_to_db(record, data)

      defp save_to_db(nil, data) do
        IO.inspect data
        changeset = __MODULE__.changeset(data)
        IO.inspect changeset
        case Repo.insert(changeset) do
          {:ok, struct}        -> struct
          {:error, changeset} -> {:error, "Insert #{__MODULE__} failure!", changeset}

      defp save_to_db(record, data) do
        case String.equivalent?(record.hash, data.hash) do
          true -> record
          _    -> update(record, data)

      defp update(record, data) do
        changeset = __MODULE__.changeset(data, record)
        case Repo.update(changeset) do
          {:ok, struct}        -> struct
          {:error, changeset} -> {:error, "Update #{__MODULE__} failure!", changeset}


This macro is included in my models. Are you see some mistakes?


I seriously cannot understand what exactly are you trying to achieve.

Instead of giving us details about your code, can you tell us what is your input and desired output?


Hi, my goal is to store API data in DB. Data is big, so I decided to update them only if there is difference (cause update is very slow operation). My input data is models like Country{Name}, League{Name,Country}, Team{Name,Venue,League}, Fixtures{TeamA,TeamB,Date} and so on. And I do not want to write comparrisions manualy (it`s a ton of code).