如何在Ecto迁移中动态更新字段值? [英] How to update field value dynamically in Ecto migration?

查看:105
本文介绍了如何在Ecto迁移中动态更新字段值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用户表,例如:

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...

中的 u from(u (在MyApp.User中)是数据库中的记录。您无法在Elixir代码中访问它。可能可以使用 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆