KiKi

KiKi

Adding and removing elements from jsonb field using embedded schema

I’m working on a small project where I’m trying to learn how to use embedded schemas. So I have albums and tracks. Album can have many tracks and they are saved in jsonb field using embedded schema. I want to be able to add new tracks and also, delete them.

In create_track() function, first I get existing tracks, then there is a map with a new track and then they both get merged, put into changeset and album get updated.

def create_track(%Album{} = album, attrs \\ %{}) do
    existing_tracks = album.tracks
    
    new_track = 
      %TrackEmbed{
        # this is just to show how TrackEmbed looks, real data comes from attrs
        name: "track name"
      }
      
    tracks = [new_track | existing_tracks]
    changeset = Ecto.Changeset.change(album)

    changeset
    |> Ecto.Changeset.put_embed(:tracks, tracks)
    |> Repo.update()
  end

To delete a track, I get existing tracks, find a list index where track I want to delete is and then I remove it from the list and the album gets updated.


def delete_track(%Album{} = album, attrs \\ %{}) do
    existing_tracks = album.tracks
    
    # real data comes from attrs here too
    existing_track_index = Enum.find_index(existing_tracks, fn x -> x.name == "track name" end)
    
    tracks = List.delete_at(existing_tracks, existing_track_index)
    changeset = Ecto.Changeset.change(album)

    changeset
    |> Ecto.Changeset.put_embed(:tracks, tracks)
    |> Repo.update()
end

The code I have here works but here I’m getting an existing list and just adding or removing from it, so I was wondering if there is maybe a better way?

Marked As Solved

dimitarvp

dimitarvp

Nothing dramatically better exists, as far I am aware. You could use cast_embed but that doesn’t help you much because you would still need to load the old value of the list and then update it, meaning that put_embed is the better choice here since it assumes the exact same use case.

cast_embed would be a good choice if you were receiving an entirely new list with which overwrites the old one (and usually if that new list is coming from external request).

Last Post!

dimitarvp

dimitarvp

Well, if you are storing things in PostgreSQL you could reach for its various JSON functions: PostgreSQL: Documentation: 13: 9.16. JSON Functions and Operators

This SO thread might help a bit in orienting you how are they used: https://stackoverflow.com/questions/23490965/postgresql-remove-attribute-from-json-column

This one seems to give you info on how to delete an object inside a JSONB array by index: https://dba.stackexchange.com/questions/164869/delete-an-object-from-within-an-array-using-jsonb-in-postgresql

(Not very useful if you don’t have the index though.)

But I’d strongly caution against poking in the guts of your DB with DB-specific functions unless you can gain a big performance win. Say if you notice that the requests to your app that are supposed to delete tracks have abnormally high latency (which in Elixir/Phoenix land basically means anything above 30ms :003:) then it’s worth the pursuit. Otherwise I wouldn’t.

Where Next?

Popular in Questions Top

hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
Lily
In templates/appointment/index.html.eex: <%= for appointment <- @appointments do %> <tr> <td><%= appoi...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
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
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
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New

Other popular topics 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
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

We're in Beta

About us Mission Statement