ruby 如何使用ActiveRecord将索引的PostgreSQL字符串列迁移到索引的字符串数组?

rekjcdws  于 2023-04-11  发布在  Ruby
关注(0)|答案(1)|浏览(117)

在我们的数据库中,我们目前有一个表,其中包含String country列。这存储了单个国家代码(例如US)。country列有一个索引。我们现在需要在列中存储多个国家代码,因此我们想将其转换为PostgreSQL String数组。我目前的迁移代码是

def change
    reversible do |direction|
      change_table :product do |table|
        direction.up do
          table.remove_index(:country)
          table.rename :country, :countries
          table.change :countries, :string, array: true
          table.index :countries
        end

        direction.down do
          table.remove_index(:countries)
          table.change :countries, :string, array: false
          table.rename :countries, :country
          table.index :country
        end
      end
    end
  end

然而,当我运行迁移时,我得到错误

PG::DatatypeMismatch: ERROR:  column "countries" cannot be cast automatically to type character varying[]
HINT:  You might need to specify "USING countries::character varying[]"

我不确定如何指定我希望如何执行转换。
我想知道如何更改迁移,以便

  1. countries列是一个数组
  2. countries列已编入索引
  3. country列的现有字符串值保存到数组中
    或者换句话说
country: 'US'

成为

countries: ['US']
5kgi1eie

5kgi1eie1#

这不是执行此类迁移的安全方法。您应该改为:

  1. Create a migration在表中创建一个新列:
class AddCountriesToProduct < ActiveRecord::Migration
  def change
    add_column :countries, :product, :string, array: true, default: []
  end
end

1.更新模型以并发写入两列,例如在after_save回调中,以便将对country的更改传播到countries。此时,两列将不会完全同步。
1.保存每个产品记录(例如,Product.find_each(&:save!)),以便触发回调,将值从country推送到countries。此时,两列将完全同步。
1.更新您的应用,使其不再使用country属性,而仅使用countries属性。之后,两列将不再同步,但countries将具有正确的值。
1.创建迁移以从表中删除旧列:

class RemoveCountryFromProduct < ActiveRecord::Migration
  def change
    remove_column :country, :product
  end
end

完成这些步骤后,就可以开始使用countries列存储多个字符串。
几个注意事项:

  • 如果您不介意锁定表并且可以处理停机时间,那么可以在一次迁移中完成所有操作,但是对于安全的在线迁移,您不希望这样做。
  • 您的表名为product而不是products,这违反了Rails的约定。

相关问题