Ecto - 将 table 列迁移到它自己的连接 table 中(将数据转移到新的 tables)

Ecto - migrate table column into its own join table (shifting the DATA to the new tables)

我想从这里开始:

  schema "products" do
    field :name, :string
    field :brand, :string
    ...more fields...
  end

为此:

  schema "products" do
    field :name, :string
    ...more fields...
  end

  schema "brands" do
    field :name, :string
    ...more fields...
  end

  schema "product_brand_joins" do
    field :p_id, :integer
    field :b_id, :integer
    ...more fields...
  end

不会丢失我当前的数据,其中包含带有字符串 :brand 字段的产品。

我了解如何创建新品牌 table 和 product_brand_joins table 并通过外迁移从产品 table 中删除“:brand”。但是有没有办法将我当前的数据操纵到新的 table 中?

您可以使用 execute/1execute/2 函数执行 SQL 语句,接受两个参数的那个是第一个参数的可回滚版本,它期望执行语句迁移时执行,回滚时执行。

因此,您可以使用它来定义迁移时应该发生的事情,这变成了定义语句的问题。 this docs page from PostgreSQL末尾有一个基于子查询插入的例子,我们将在这里使用。

在您的迁移 .exs 文件中:

use Ecto.Migration

def up do
  create table(:brands) do
    add :name, :string,
    # add other fields
  end

  create table("product_brand_joins") do
    add :product_id, references: :products
    add :brand_id, references: :brands
  end

  # Insert into the brands table a brand with each name found in products
  execute(
    "INSERT INTO brands(name) 
      SELECT DISTINCT(brand) FROM products"
  )

  # Insert into the joined table the product and brand ids
  execute(
    "INSERT INTO product_brand_joins(product_id, brand_id)
      SELECT p.id, b.id FROM products p LEFT JOIN brands b ON p.brand = b.name"
  )

  # And finally delete the column from products
  alter table(:products) do
    remove :brand
  end
end

然后对于回滚,您将在迁移中实现 down 函数以使用类似的逻辑恢复过程:在 products 中创建品牌列,并用相应的名称填充它品牌取决于产品 ID,并删除新表。