jmurphyweb

jmurphyweb

Old migrations error with updated/current schema

I’ve run into this a couple of times and am wondering if I’m approaching data migrations wrong.

A week ago I had an Offer schema:

  schema "offers" do
    field(:regular_site_id, :id)
  end

I want to update offers with a regular_site_id, then add a NOT NULL constraint to the regular_site_id column:

  def up do
    offer_query = from(o in Offer, where: is_nil(o.regular_site_id))
    
    offer_query
    |> Repo.all()
    |> update_each_offers_regular_site()

    flush()
    
    alter table(:offers) do
      modify(:regular_site_id, :id, null: false)
    end
  end

This all runs fine, all environments now have run the above migration. But now I want to write a new migration:

  def up do
    alter table(:offers) do
      add(:something_new, :string, null: false)
    end
  end

Adding a field to the offer so the schema now looks like:

  schema "offers" do
    field(:regular_site_id, :id)
    field(:something_new, :string)
  end

Replicating our CI, which attempts to build out the database from scratch, if I run MIX_ENV=test mix ecto.reset I will get an error:

** (Postgrex.Error) ERROR 42703 (undefined_column): column o0.something_new does not exist
    (ecto) lib/ecto/adapters/sql.ex:431: Ecto.Adapters.SQL.execute_and_cache/7
    (ecto) lib/ecto/repo/queryable.ex:133: Ecto.Repo.Queryable.execute/5
    (ecto) lib/ecto/repo/queryable.ex:37: Ecto.Repo.Queryable.all/4
    priv/repo/migrations/20190406130008_add_regular_site_ids.exs:10: Ev2.Repo.Migrations.AddRegularSiteIds.up/0
    (stdlib) timer.erl:197: :timer.tc/3
    (ecto) lib/ecto/migration/runner.ex:25: Ecto.Migration.Runner.run/6
    (ecto) lib/ecto/migrator.ex:128: Ecto.Migrator.attempt/6
    (ecto) lib/ecto/migrator.ex:72: anonymous fn/4 in Ecto.Migrator.do_up/4

I can get around this by just commenting out the data migration part, which is ok because the migration has now run in all environments.

But it seems like this would be a fairly common issue, am I approaching the data migration wrong? The problem would also go away if I wrote the migration with pure SQL but that isn’t always possible.

Marked As Solved

hubertlepicki

hubertlepicki

This is your problem right here. You are using piece of your application code, i.e. schema that has added new fields in it, and expect them to be present in database. This works once, in the time you write the new migration, but will fail likely later wien Offer schema is changed in your application, and no longer matches whatever the migration is expecting to find there.

The rule of thumb I am applying is: only use migration DSL and “execute” statements in migrations. If you have to alter some data in database just write:

execute "UPDATE .... " 

with hand-written SQL instead of using your Ecto schemas.

Possibly you could also use Ecto.DSL if you really want here, with “shemaless query” but I did never attempt this (Ecto’s insert_all and schemaless queries « Plataformatec Blog)

Where Next?

Popular in Questions Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

Other popular topics Top

Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New

We're in Beta

About us Mission Statement