drapermd

drapermd

Upsert map in jsonb map array

So here is the code I came up with to generically generate an array param that will be stored on a jsonb property in ecto.

It only handles the root level, and is pretty limited, but I’m curious if the community has a better/more elegant/easier solution than I do. Let me re-phrase, I really believe you do, I just wanted to solicit advice.

Problem: jsonb array of objects stored on an Ecto model, these objects can be updated or added.

  @doc "if the id is in the map already, update it, otherwise append it"
  defp upsert_embed(%{id: id} = params, collection) when is_list(collection) do
   case Enum.find(collection, &(&1.id == id)) do
     nil -> collection ++ [params]
     found -> updated = Map.merge(found, params)
              collection = collection -- [found] ## This is the piece I'm really not confident in.
              collection = collection ++ [updated]
   end
  end
  @doc "provided map doesn't have an id"
  defp upsert_embed(%{} = params, collection) when is_list(collection) do
    collection ++ [params]
  end

  @doc """
  adds or updates a child object of an array of maps.
  """
  def upsert_embedded_field(%__struct__{} = struct, key, %{} = candidate_params) do
    updated_embeds = Map.get(struct, key) || []
    updated_embeds = case length(updated_embeds) do
       0 ->
          upsert_embed(candidate_params, updated_embeds)
       _ ->
          updated_embeds = Enum.reduce(updated_embeds, updated_embeds,  fn(e, collection) ->
            upsert_embed(candidate_params, collection)
          end)
       end
     # Return the mutated list
      updated_embeds
  end

Most Liked

drapermd

drapermd

Unfortunately Mongodb has serious security problems, and has had data retention issues in the past and honestly very slow for map reduce, search and math. I’ve deployed 6-9 apps on MongoDB and I like it for some things, but in my day job we have been urged to move all apps off of Mongo as soon as possible so when it comes to my hobby projects I am veering away from it now completely.

Postgres is vastly more feature-rich, time tested, performant, and out-performs Mongo for most NoSQL operations. I will switch frameworks before I switch the datastore. Languages come and go, but data storage is too important to make concessions on, and with Postgres there is no compromise, it just does exactly what I need it to do.

Now if only Ecto were as feature-rich :smiley:

mudasobwa

mudasobwa

Creator of Cure

NoSQLMongoDB though.

CouchDB is pure erlang. Also, Riak, Cassandra, RethinkDB and many more.

sorentwo

sorentwo

Oban Core Team

There are Postgres operators to do this directly on the jsonb column in an atomic way. You will need to use a fragment and play with the arguments a little bit.

The list of operators is in the postgresql docs. You are looking for jsonb_set in particular.

The Postgres adapter in my Flippant library has an example of doing upsert with an array on a jsonb column:

https://github.com/sorentwo/flippant/blob/master/lib/flippant/adapters/postgres.ex#L79

It is a bit complicated but works perfectly and is entirely atomic.

Last Post!

drapermd

drapermd

Is there robust ecto support for couchdb?

Where Next?

Popular in Guides/Tuts Top

mhanberg
Hi! I recently finished adding authentication to my Phoenix API, so I wanted to share what I learned. I haven’t created authentication f...
New
dogweather
I just finished a long process of configuring and debugging a Docker Compose-based dev environment. Several late-night hours! I think I’v...
New
zenw0lf
Hello all! For those wanting to try your hands at Elixir / Phoenix, I wrote a comprehensive tutorial on doing a simple JSON API with sai...
New
marcelo
I wrote a small article on how to use current_user with coherence on Phoenix. There are already a couple of blogposts about it but I thin...
New
hauleth
Some time ago someone suggested me to write article about how I have configured my Vim to work with Elixir, now there it is: https://med...
New
anuragg
We just published a guide to automatic clustering in Elixir 1.9, with Mix releases and libcluster. The cluster automatically discovers n...
New
Morzaram
Hey guys I’ve made a guide on how to connect Quill to Phoenix. For the sake of formatting it might be easier to view it on my Notion Doc...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 130286 1222
New
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
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
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 54006 488
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New

We're in Beta

About us Mission Statement