unlogic

unlogic

Insert or update with separated results

I have an API that allows users to update and insert items with a single request. It works by supplying a list of JSON objects to an endpoint that will update items where the primary key exists, and insert new items where the primary key doesn’t exist. I have this working with:

def create_machines(attrs) do
    x =
      attrs
      |> Enum.map(fn x -> get_changeset(x) end)
      |> Enum.map(fn x -> Repo.insert_or_update(x) end)
  end

  defp get_changeset(params) do
    case Repo.get_by(Machine, name: params["name"]) do
      nil ->
        # Insert a new machine
        Machine.changeset(%Machine{}, params)

      machine ->
        # Update the machine data
        Machine.changeset(machine, params)
    end
  end

I get back a list of {ok: Machine} items. What I would like to have though is a list of updated machines and a list of new machines so that the returned JSON is something like

{
  "new": 
    [
      {"name": "machine1", ...}, {...}
    ], 
  "updated": 
    [
      {"name": "machine2", ....}, .{...} 
    ] 
}

I’m just not sure how best to approach generating this result properly. I’ve tried inserting or updating the changeset in the get_changeset function so that I can return something like {:update, machine} and {:create, machine} but then I got stuck with trying to convert

[{:update, machine1}, {:update, machine2}, {:created, machine3}] 

Into the format above for display.
Any advice on what the best approach is for this? thanks

Marked As Solved

al2o3cr

al2o3cr

Enum.group_by will get you close to what you want:

iex(4)> [{:updated, "foo"}, {:updated, "bar"}, {:created, "baz"}, {:updated, "wat"}] |> Enum.group_by(fn {x, _} -> x end)
%{
  created: [created: "baz"],
  updated: [updated: "foo", updated: "bar", updated: "wat"]
}

This would still require some postprocessing of the individual lists to remove the {:created, _} wrappers around the internal elements.

Alternatively, you could use Enum.reduce with an initial state of %{new: [], updated: []} and compute what you want directly.

Last Post!

unlogic

unlogic

Thank you for your reply. I ended up going with the reduce as it seemed simpler

attrs
    |> Enum.reduce(%{new: [], updated: []}, fn x, acc ->
      case Repo.get_by(Machine, name: x["name"]) do
        nil ->
          # Insert a new machine
          {:ok, machine} = Repo.insert(Machine.changeset(%Machine{}, x))
          new_list = acc.new ++ [machine]
          %{new: new_list, updated: acc.updated}

        machine ->
          # Update the machine data
          {:ok, machine} = Repo.update(Machine.changeset(machine, x))
          updated_list = acc.updated ++ [machine]
          %{new: acc.new, updated: updated_list}
      end
    end)

Where Next?

Popular in Questions Top

electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 44778 311
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

We're in Beta

About us Mission Statement