elixir - Ecto迁移中如何动态更新字段值?

标签 elixir ecto

我有一个用户表,例如:

     email     | username
---------------+----------
 123@321.com   |
 123@123.com   |
 haha@haha.com |

我想通过电子邮件字段更新用户名字段,只需在@之前切片电子邮件即可。

     email     | username
---------------+----------
 123@321.com   | 123
 123@123.com   | 123
 haha@haha.com | haha

我尝试使用以下迁移:

defmodule MyApp.Repo.Migrations.AddDefaultUsernameForUsers do
  use Ecto.Migration
  import Ecto.Query

  def up do
      from(u in MyApp.User, update: [set: [username: String.split(u.email, "@") |> List.first ]])
        |> MyApp.Repo.update_all([])
  end

  def down do
      MyApp.Repo.update_all(MyApp.User, set: [username: nil])
  end
end

但是在运行迁移时,我收到以下错误:

$ mix ecto.migrate
** (Ecto.Query.CompileError) `List.first(String.split(u.email(), "@"))` is not a valid query expression

我该如何解决这个问题?

最佳答案

@Justin Wood 已经解释了为什么不能在更新查询中使用 Elixir 函数,所以我不再重复。在 PostgreSQL 中,您可以使用带有正则表达式的 substring 函数提取 @ 之前的文本,这将与更新查询一起使用。这比加载记录然后逐一更新它们要快得多,但如果不调整 SQL 片段,则无法与其他数据库引擎一起使用:

from(u in MyApp.User,
  update: [set: [username: fragment("substring(? from '^(.*?)@')", u.email)]])
|> MyApp.Repo.update_all([])
postgres=# select substring('123@321.com' from '^(.*?)@');
 substring
-----------
 123
(1 row)

关于elixir - Ecto迁移中如何动态更新字段值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44098069/

相关文章:

elixir - 将 LEFT OUTER JOIN 查询转换为 Ecto

elixir - Elixir 中的自定义类型

postgresql - 查询 View 和函数

elixir - 使用带有子查询的 Ecto 进行预加载并使用主查询中的联接

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

elixir - Elixir 新手 - 连接两个列表

elixir - 使用 via 元组注册 GenServer 时遇到问题。 ** (UndefinedFunctionError) 函数 PokerServer.whereis_name/1 未定义或私有(private))

elixir - 如何在 Phoenix 的 channel 上启用压缩?

elixir - 在 Elixir 中,有没有办法确定模块是否存在?

elixir - 如何在 GenServer 中执行对当前进程的调用?