【问题标题】:Elixir Ecto - How to Upsert/IncrementElixir Ecto - 如何 Upsert/Increment
【发布时间】:2017-02-10 03:35:10
【问题描述】:

我想在 Phoenix/Elixir 中执行一个模型。该模型基本上计算用户花费的金额的滚动总和。模型 (Receipts) 如下所示:

---------------
| ID | Amount |
---------------
| 1  |   0    |
| ...|  ...   |
| 5  |   4    |
---------------

ID 上有一个唯一索引。我想在表中插入一个用户(我定义了 ID),然后如果用户不存在则设置金额,否则将新金额添加到现有金额中。例如,执行:

Repo.insert(Users.changeset(%Users{}, %{ID: 1, Amount: 10})

会导致:

---------------
| ID | Amount |
---------------
| 1  |   11   |
| ...|  ...   |
| 5  |   4    |
---------------

并执行 Repo.insert(%Users{}, Users.changeset(%{ID: 6, Amount: 5}) 将导致:

---------------
| ID | Amount |
---------------
| 1  |   11   |
| ...|  ...   |
| 5  |   4    |
| 6  |   5    |
---------------

我知道我应该对:on_conflict 做点什么,但我有点迷失如何正确处理它。谁能指出我正确的方式?

【问题讨论】:

    标签: elixir phoenix-framework ecto


    【解决方案1】:

    当然,这是可能的。它看起来像这样:

    iex> amount_to_add = 10
    10
    iex> Repo.get(User, 1)
    nil
    iex> Repo.insert(%User{id: 1, amount: amount_to_add}, conflict_target: :id, on_conflict: [inc: [amount: amount_to_add]])
    ...
    iex> Repo.get(User, 1)
    %User{id: 1, amount: 10, ...}
    iex> Repo.insert(%User{id: 1, amount: amount_to_add}, conflict_target: :id, on_conflict: [inc: [amount: amount_to_add]])
    ...
    iex> Repo.get(User, 1)
    %User{id: 1, amount: 20, ...}
    

    【讨论】:

      【解决方案2】:
      Repo.transaction fn ->
        user =
          User
          |> where(id: ^id)
          |> lock("FOR UPDATE")
          |> Repo.one()
      
        if user do
          user
          |> change(amount: user.amount + 5)
          |> Repo.update!()
        else
          %User{}
          |> change(amount: 5)
          |> Repo.insert!()
        end
      end
      

      这是一种使用 postgreSQL 语法进行锁定的方法。我想你会弄清楚其余的。

      【讨论】:

        【解决方案3】:

          添加到第一个答案 更新后返回变量将防止并行问题。

        iex> Repo.insert(%User{id: 1, amount: amount_to_add},  returning: [:amount], conflict_target: :id, on_conflict: [inc: [amount: amount_to_add]])
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-10-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-01-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多