Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elixir Ecto - How to Upsert/Increment

I have a model that I would like to execute in Phoenix/Elixir. The model basically computes a rolling sum of the amount spent by a user. The model (Receipts) looks like the following:

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

There is a unique index on ID. I want to insert a user into the table (I define the ID) and then set the amount if the user does not exists, otherwise add the new amount to the existing amount. For example, executing:

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

Would result in:

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

and executing Repo.insert(%Users{}, Users.changeset(%{ID: 6, Amount: 5}) would result in:

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

I know that I should be doing something with :on_conflict but I'm a bit lost how to get it right. Can anyone point me in the right way?

like image 462
user2694306 Avatar asked Dec 06 '22 15:12

user2694306


1 Answers

Sure, that's possible. It would look something like this:

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, ...}
like image 161
stoodfarback Avatar answered Dec 19 '22 00:12

stoodfarback