使用单一迁移更新数据库?

updating the database with single migration?

我有一个 table 有一个“项目”,该项目有一个采用字符串数组的字段工作区。所以我将其转换为存储单个字符

 create table("projects") do
  add(:name, :string, null: false)
  add(:title, :string, null: false)
  add(:workspaces, {:array, :string})

  timestamps()
end

我编写此迁移是为了存储单个字符串

alter table(:projects) do
      modify(:workspace, :string)

我想 运行 此迁移,但我还想更新存储在数据库中的所有数据。我需要更新所有工作区数据以存储单个字符串。

假设工作区是否有这个值{value1, value2}。它将寻找 value1,如果找到它,它将存储 value1,否则它将存储 value2

这就是 {value1, value2} 它在数据库 table 中的存储方式。所以当我们将它加载到 elixir 中时,它看起来像这样 ["value1", "value2"]

我可以在这里做什么?

您似乎正试图在关系数据库中创建一个 schema-less 数据库。这很快就会变得困难。使用像 couch 或 mongo.

这样的无模式数据库可能会更好

但是,如果您使用的是 postgres,jsonb 或 json 列类型将更好地服务于此用例 IMO。数据有点难以查询,因为 postgres operators 很有趣,但一旦你仔细研究它,它就不会太糟糕,适当索引的性能将与无模式相媲美。此外,您还可以获得不必将 serializing/deserializing 写入数据库层的额外好处。

如果我没理解错的话,您想将 workspaces 数组列更改为包含数组第一个元素的 workspace 字符串列。如果是这种情况,您可以在迁移中执行类似的操作:

# Add the `workspace` column:
alter table(:projects) do
  add(:workspace, :string)
end

# Set the value of the new column:
execute("""
  UPDATE projects SET workspace = CASE
    WHEN 'value1' = ANY(workspaces) THEN 'value1'
    WHEN 'value2' = ANY(workspaces) THEN 'value2'
    ELSE 'default_value'
    END
  """)

# Remove the old column
alter table(:projects) do
  remove(:workspaces)
end