Updating a Nested Map in a Schema

I am currently having problems trying to update a nested map in a Schema since it doesn’t allow for Access behaviour I can’t just Kernel.put_in etc…

My Schema is as follows:

> %PhoenixApi.Schema.Test{
>   __meta__: #Ecto.Schema.Metadata<:loaded, "test_table">,
>   id: 1,
>   delete: false,
>   person: %{
>     "city" => %{"55" => "London"},
>     "name" => "john cena"
>     "address" => "55 Test Drive"
>   }
> }

I use get_test(id) to retrieve this information, but I would like to change the persons name and city before updating it/sending it back into my table.
This person is stored as a :map in the schema.
I know update needs a changeset to work, it’s how to make the changes in the changeset for Ecto.update and updating nested maps in structs is confusing me, sorry.
Thank you for reading.

I have created a workaround? method?

I pattern match out of the get_test(id).

old_person = get_test(id)
%{id: id, delete: delete, person: person} = old_person
new_person = %{id: id, delete: delete, person: person}

Then I can use:
new_person = Kernel.put_in(new_person, [:person, "name"], "New Name")
because it is purely just a map now and not a Schema, then update row via the auto generated context function update_person:

> def update_person(%Test{} = test, attrs) do
>     test
>     |> Test.changeset(attrs)
> 	|> Repo.update()
>   end


update_person(old_person, new_person)

and BAM it’s updated.
If anyone has any improvements I would love to hear them!

You may also look into embeds_one to have your map treated as an embedded schema, with defined fields/changeset.

As for what you’ve achieved, that what I would do for a bare map too.

1 Like