我如何迁移索引的PostgreSQL字符串列到一个索引数组的字符串使用ActiveRecord? &g



在我们的数据库中,我们目前有一个字符串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']

这不是进行这种迁移的安全方法。你应该:

  1. 创建一个迁移,在表上创建一个新列:
class AddCountriesToProduct < ActiveRecord::Migration
def change
add_column :countries, :product, :string, array: true, default: []
end
end
  1. 更新您的模型以并发地写入两个列,例如在after_save回调中,以便对country的更改传播到countries。此时,这两列将不会完全同步。
  2. 保存每个产品记录(例如,Product.find_each(&:save!)),以便触发回调,将值从country推到countries。此时,两个列将完全同步。
  3. 更新你的应用程序,使它不再使用country属性,只使用countries属性。在此之后,两列将不再同步,但countries将有正确的值。
  4. 创建迁移以从表中删除旧列:
class RemoveCountryFromProduct < ActiveRecord::Migration
def change
remove_column :country, :product
end
end

完成这些步骤后,您可以开始使用countries列来存储多个字符串。

注意事项:

  • 如果你不介意锁表并且可以处理停机,那么可以在一次迁移中完成所有事情,但是对于安全的在线迁移,你不想这样做。
  • 你的表被命名为product而不是products,这打破了Rails的惯例。在这个例子中我尊重你的表名,但是你应该考虑修复这个问题。

最新更新