【问题标题】:Rails migration array without default没有默认的 Rails 迁移数组
【发布时间】:2019-11-23 21:01:11
【问题描述】:

Rails 5,Postgres 9

我有超过 1000 万条模型记录。我需要添加具有数组类型的新字段。 从文档中我可以添加新的迁移为

add_column :model, :new_field, :string, array: true, default: []

但是在它之后,由于许多设置默认值的 Alter 操作,数据库被阻塞了。

创建没有(默认:[])值的新数组字段是真的吗?

【问题讨论】:

  • 不管怎样,postgresql 中的默认值不是一个空数组,那为什么要明确指定呢?

标签: ruby-on-rails postgresql migration


【解决方案1】:
  1. 在表中添加一列默认值为null
  2. 批量更新行(默认1000)并设置[]为值
  3. 在列上设置NOT NULL

class AddCategoriesToProducts < ActiveRecord::Migration[6.0]
  disable_ddl_transaction!

  def up
    ActiveRecord::Base.transaction do
      add_column :products, :categories, :string, array: true

      execute <<~SQL
        ALTER TABLE products ALTER COLUMN categories SET DEFAULT '{}';
      SQL
    end

    Product.find_in_batches(batch_size: 1000).with_index do |products, index|
      puts "Processing #{index + 1}"
      Product.where(id: products.map(&:id)).update_all(categories: [])
    end

    ActiveRecord::Base.transaction do
      execute <<~SQL
        ALTER TABLE products ALTER COLUMN categories SET NOT NULL;
      SQL
    end
  end

  def down
    ActiveRecord::Base.transaction do
      remove_column :products, :categories
    end
  end
end

这是一个缓慢的迁移,您必须等待它完成,但它会阻止锁定表。

【讨论】: