我有一个用户表,例如:
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/