gpt4 book ai didi

postgresql - Ecto - 使用自定义逻辑将字段迁移到不同类型的正确方法?

转载 作者:行者123 更新时间:2023-11-29 14:26:47 25 4
gpt4 key购买 nike

我有一个列 :from,它最初是 {:array, :string} 类型。现在我想将此列迁移为 :string 类型,将数组的第一个条目作为新值。

在 Rails 中,您可以在迁移中使用一些自定义逻辑来完成此操作。我正在尝试对 Ecto 做同样的事情,但由于模式验证和变更集错误而遇到了问题。

defmodule Assistant.Repo.Migrations.ChangeFromFieldOnMails do
use Ecto.Migration

def up do
dict_of_froms =
Assistant.Mail
|> Assistant.Repo.all()
|> Enum.reduce(%{}, fn mail, acc ->
Map.put(acc, mail.id, List.first(mail.from))
end)

alter table(:mails) do
remove :from
add :from, :string
end

Assistant.Mail
|> Assistant.Repo.all()
|> Enum.each(fn mail ->
changeset = Ecto.Changeset.change(mail, from: Map.get(dict_of_froms, mail.id))
Assistant.Repo.update!(changeset)
end)
end

def down do
dict_of_froms =
Assistant.Mail
|> Assistant.Repo.all()
|> Enum.reduce(%{}, fn mail, acc ->
Map.put(acc, mail.id, [mail.from])
end)

alter table(:mails) do
remove :from
add :from, {:array, :string}
end

Assistant.Mail
|> Assistant.Repo.all()
|> Enum.each(fn mail ->
changeset = Ecto.Changeset.change(mail, from: Map.get(dict_of_froms, mail.id))
Assistant.Repo.update!(changeset)
end)
end
end


问题是,我还必须将 field :from, {:array, :string} 更改为 field :from, :string Mail 架构,这会导致验证出现问题。

up 步骤中,Assistant.Repo.all() 会失败,因为 Ecto 无法从旧数据库加载 from 字段类型不匹配。

down 步骤中,Assistant.Repo.update!(changeset) 会失败,因为 Ecto.Changeset 报告类型不匹配错误:来自

在 Rails 中,并没有真正严格的架构检查,因此您可以不用编写代码。

使用 Ecto 执行此类迁移的正确方法是什么?除了编写自定义 SQL 之外没有其他方法吗?

最佳答案

您需要避免在迁移中使用结构和变更集。请改用 Repo.insert_allRepo.update_all 和模式命名。

defmodule Assistant.Repo.Migrations.ChangeFromFieldOnMails do
use Ecto.Migration
import Ecto.Query

def up do
dict_of_froms =
"mails" # table name as string
|> Assistant.Repo.all()
|> Enum.reduce(%{}, fn mail, acc ->
Map.put(acc, mail.id, List.first(mail.from))
end)

alter table(:mails) do
remove :from
add :from, :string
end

dict_of_froms
|> Enum.each(fn {id, from} -> # changed this cycle little bit, so it would
"mails" # update record only if we have `from` for it
|> where(id: ^id)
|> update(set: [from: ^from])
|> Repo.update_all()
end)
end

def down do
dict_of_froms =
"mails"
|> Assistant.Repo.all()
|> Enum.reduce(%{}, fn mail, acc ->
Map.put(acc, mail.id, [mail.from])
end)

alter table(:mails) do
remove :from
add :from, {:array, :string}
end

dict_of_froms
|> Enum.each(fn {id, from} -> # changed this cycle little bit, so it would
"mails" # update record only if we have `from` for it
|> where(id: ^id)
|> update(set: [from: ^from])
|> Repo.update_all()
end)
end
end

不确定所有代码是否干净且可编译,但希望我的想法很清楚

关于postgresql - Ecto - 使用自定义逻辑将字段迁移到不同类型的正确方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56992383/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com