Question Concerning Ecto Multi

I have a question concerning ecto. Please help recommend.
I am needing to generate an sequences of database operations dynamically and in a single transaction and response back the result as an api.
Let’s suppose I am using the method below to generate a multi -

list_of_params = [%{params1...}, %{params2...}... ]

multi =

#Generate a sequence of multi operations as below -

{multi, last_index} = List.foldl(list_of_params,{multi, 0}, fn (params, {multi, index}) ->
multi = multi
|> Ecto.Multi.insert(String.to_atom("result_#{index}"), Repo.insert(Something.changeset(item)) )

By using this I am able multi from a list.

I have a little issues here. I would like the failing or success result back to list. How could I do that

I am using multi here because if I use insert_all, my timestamps will not be updated and I have some database operations together with has to go with this database transaction.

Could you help figure out how to convert variable result_1, result_2, result_3 to the result list.
Or could you recommend any another way. I would like to get back result as a list.


There are a couple issues here.

  • Your fold function expects to receive a {Ecto.Multi.t, non_neg_integer}, but you seem to be returning just an Ecto.Multi.t. I’m not sure if this an actual error in your code, or just in your example.
  • You should (almost) never use String.to_atom/1.
    • There is un upper limit to how many atoms you can have in your system. The default is 1,048,576 (220).
    • Atoms are never garbage collected. It is possible that you would be able to OOM (Out Of Memory) your machine by doing this.
  • Just because you are using a fold does not mean you are unable to return a list.For example, you can do the following
iex(1)> my_list = [1,2,3,4]
[1, 2, 3, 4]
iex(2)> List.foldl(my_list, [], fn elem, acc -> [elem | acc] end)
[4, 3, 2, 1]

Which is a perfectly acceptable way to reverse a list.

As for wanting the value of result_n, Ecto.Multi.insert/4 returns an Ecto.Multi. You are unable to see from the return of that function whether or not the query failed. You will only see the overall result after running MyApp.Repo.transaction/2.

1 Like

it’s not about the foldl and Atom limits that i am having problem with here. i did make that parts work.

now i need to make result_1, result_2 and so on to result of type list.


I realize your question was not about the atom limit. But I was unaware if you already knew about it. So I figured I should at least mention it.

To answer your question again, you have to actually run MyApp.Repo.transaction/2 in order to get the results of the transaction. Before running MyApp.Repo.transaction/2, none of your database operations are actually run. You can read more about it in the documentation.

1 Like

Thank you @ankhers for recommending about atom limit.
In this case I am having little worried about the atom size due to I am not generating in randomly. and I am reusing this atom again when there are these transaction to happen. as you can see I am using pattern of result_1, result_2 … for the atoms.

I forget to mentioned earlier I was actually stuck at the step after MyApp.Repo.transaction/2 has been executed.

when we get back (when fail) {:error, fail_operation, fail_value, changes_so_far}. In my case the the change so far will be in the form of %{result_1: result1, result_2: result2… }

or when(success) we will get {:ok, %{result_1: result1, result_2: result2}}

I am looking for ways to convert results into result list. that is result1, result2, result3 to result = []

Thank you

I think I solve this by instead of pattern matching the results_so_far keys(:result_1, :result2) to variables. I could take in it as a whole.
And since I already has the last index from the foldl result.

I could use something like this to solve my problem.

foldl (results_so_far, [], fn elem, acc ->
  [elm | acc]

I think that could work.

You could also simply use Map.values(results_so_far).

Thank you @Ankhers. That will works for me.