如何在Ecto迁移中动态更新字段值? [英] How to update field value dynamically in Ecto migration?
问题描述
我有一个用户表,例如:
I have a Users table like:
email | username
---------------+----------
123@321.com |
123@123.com |
haha@haha.com |
,我想通过以下方式更新用户名
字段电子邮件
字段,只需将电子邮件
切片在 @
之前。 / p>
and I want to update username
field by email
field, just slice the email
before @
.
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
但是在运行迁移时,出现以下错误:
But when runing the migration, I got the following error:
$ mix ecto.migrate
** (Ecto.Query.CompileError) `List.first(String.split(u.email(), "@"))` is not a valid query expression
我该如何解决
推荐答案
您将要进行两个单独的查询。第一个查询获取数据,执行所需的任何更改,然后第二个查询更新该数据。
You are going to want to make two separate queries. One query to grab the data, do whatever changes you want, then a second query to update that data. Something along the lines of
Repo.all(MyApp.User)
|> Enum.map(fn u ->
username =
u.email
|> String.split("@")
|> List.first()
Ecto.Changeset.cast(u, %{username: username})
end)
|> Repo.update_all()
关于为什么您不能做自己的事情有两件事
There are a couple things going on as to why you cannot do what you were attempting to do.
当您想在Ecto查询中使用Elixir函数或值时,通常必须使用pin运算符( ^
)。因此,如果要查询特定的ID,可以使用 from(MyApp.User中的u,其中:u.id == ^ 12)
。因此,您的反应可能是尝试使用 ^ List.first(String.split(u.email, @))
。但是,这将不起作用,因为...
When you want to use an Elixir function or value within an Ecto query, you would normally have to use the pin operator (^
). So if you wanted to query for a specific ID, you could use from(u in MyApp.User, where: u.id == ^12)
. So your reaction may be to try and use ^List.first(String.split(u.email, "@"))
. However, this will not work because...
中的
是数据库中的记录。您无法在Elixir代码中访问它。可能可以使用 u
from(u (在MyApp.User中) fragment / 1
进行操作,但是您无法使用常规的Elixir函数操纵该值,直到您使用上述示例将其实际从数据库中拉出为止。
The u
in from(u in MyApp.User)
is the record as is in the database. You do not have access to it in your Elixir code. It may be possible to use a fragment/1
for what you are trying to do, but you cannot manipulate the value with regular Elixir functions until you actually pull it out of the database using something like my example above.
这篇关于如何在Ecto迁移中动态更新字段值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!