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:

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

Where Next?

Popular in Guides/Tuts Top

tfwright
I thought I’d share a small project I’m working on to gain some familiarty with LiveView in a Phoenix app. Github Repo Deployment It’s...
New
AstonJ
This blog post hit my timeline earlier, and I’ve also been learning about some fantastic Elixir related tips via @pragdave’s new online c...
New
1player
A question I had when first learning contexts and Ecto was how to expand the default context API to support more flexible queries. Usuall...
New
jswny
Hello everyone, I recently redesigned my entire deployment process for Phoenix apps based on Docker. I really like the strategy that I ca...
New
anuragg
Hi everyone! I’m the founder of Render, a new cloud provider with native support for Elixir. When we launched Elixir support the most po...
New
magnetic
Hey :wave:t3: Elixir community, I’ve been learning Elixir, and working on some side projects. My editor of choice is VSCode, and althoug...
New
bitli
In case this is handy for other people, here is how you can run Elixir on Android: Install https://termux.com/ apt update; apt upgrad...
New
anuragg
Hi everyone, I’m the founder of Render and we just released a guide to deploying Phoenix apps with Mix releases. Most of it is generali...
New
f0rest8
Hi, TLDR: form attribute set on the input fields and button submit. I just wanted to share a solution I discovered when making live inl...
New
eclark
I’ve been working on a phoenix project lately and I wanted to use the latest versions of everything. Webpack 5 had some breaking changes ...
New

Other popular topics Top

sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
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
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31107 143
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

We're in Beta

About us Mission Statement