tovarchristian21
Convert a nested struct into a nested map
Hello guys, can you please help turn this map into a pure map. Some of the members of the map are still structs.
%{
callback_query: nil,
channel_post: nil,
chosen_inline_result: nil,
edited_message: nil,
inline_query: nil,
message: %Nadia.Model.Message{
audio: nil,
caption: nil,
channel_chat_created: nil,
chat: %Nadia.Model.Chat{
first_name: "Christian",
id: 543211234,
last_name: "Tovar",
photo: nil,
title: nil,
type: "private",
username: "ChristianTovar"
},
contact: nil,
date: 1562605521,
delete_chat_photo: nil,
document: nil,
edit_date: nil,
entities: nil,
forward_date: nil,
forward_from: nil,
forward_from_chat: nil,
from: %Nadia.Model.User{
first_name: "Christian",
id: 543211234,
last_name: "Tovar",
username: "ChristianTovar"
},
group_chat_created: nil,
left_chat_member: nil,
location: nil,
message_id: 714,
migrate_from_chat_id: nil,
migrate_to_chat_id: nil,
new_chat_member: nil,
new_chat_photo: [],
new_chat_title: nil,
photo: [],
pinned_message: nil,
reply_to_message: nil,
sticker: nil,
supergroup_chat_created: nil,
text: "google meets",
venue: nil,
video: nil,
voice: nil
},
update_id: 412827321
}
Marked As Solved
Eiji
Here is example working code:
# First of all minimal definition in order to make code compillable
defmodule Nadia.Model.Chat do
defstruct [:first_name, :id, :last_name, :photo, :title, :type, :username]
end
defmodule Nadia.Model.User do
defstruct [:first_name, :id, :last_name, :username]
end
defmodule Nadia.Model.Message do
defstruct [
:audio,
:caption,
:channel_chat_created,
:chat,
:contact,
:date,
:delete_chat_photo,
:document,
:edit_date,
:entities,
:forward_date,
:forward_from,
:forward_from_chat,
:from,
:group_chat_created,
:left_chat_member,
:location,
:message_id,
:migrate_from_chat_id,
:migrate_to_chat_id,
:new_chat_member,
:new_chat_photo,
:new_chat_title,
:photo,
:pinned_message,
:reply_to_message,
:sticker,
:supergroup_chat_created,
:text,
:venue,
:video,
:voice
]
end
# Here is code which would work only for your specific case
defmodule Example do
def sample(map) do
message = ensure_map(map.message)
chat = ensure_map(message.chat)
from = ensure_map(message.from)
updated_message = %{message | chat: chat, from: from}
%{map | message: updated_message}
end
defp ensure_map(%{__struct__: _} = struct), do: Map.from_struct(struct)
defp ensure_map(data), do: data
end
# Here is more dynamic way
# No matter how many maps and lists have you nested
# It will iterate over all map or list elements and finally ensure that they are not structs
# NOTE: If you want you can add extra guard to limit possible __struct__ value
# For example you probably do not want to create maps from Date, DateTime, NaiveDateTime and Time structs
defmodule ExampleDynamic do
def sample(map), do: :maps.map(&do_sample/2, map)
def do_sample(_key, value), do: ensure_nested_map(value)
defp ensure_nested_map(list) when is_list(list), do: Enum.map(list, &ensure_nested_map/1)
# NOTE: In pattern-matching order of function guards is important!
# @structs [Date, DateTime, NaiveDateTime, Time]
# defp ensure_nested_map(%{__struct__: struct} = data) when struct in @structs, do: data
defp ensure_nested_map(%{__struct__: _} = struct) do
map = Map.from_struct(struct)
:maps.map(&do_sample/2, map)
end
defp ensure_nested_map(data), do: data
end
# Your example data which is needed for compilation
data = %{
callback_query: nil,
channel_post: nil,
chosen_inline_result: nil,
edited_message: nil,
inline_query: nil,
message: %Nadia.Model.Message{
audio: nil,
caption: nil,
channel_chat_created: nil,
chat: %Nadia.Model.Chat{
first_name: "Christian",
id: 543_211_234,
last_name: "Tovar",
photo: nil,
title: nil,
type: "private",
username: "ChristianTovar"
},
contact: nil,
date: 1_562_605_521,
delete_chat_photo: nil,
document: nil,
edit_date: nil,
entities: nil,
forward_date: nil,
forward_from: nil,
forward_from_chat: nil,
from: %Nadia.Model.User{
first_name: "Christian",
id: 543_211_234,
last_name: "Tovar",
username: "ChristianTovar"
},
group_chat_created: nil,
left_chat_member: nil,
location: nil,
message_id: 714,
migrate_from_chat_id: nil,
migrate_to_chat_id: nil,
new_chat_member: nil,
new_chat_photo: [],
new_chat_title: nil,
photo: [],
pinned_message: nil,
reply_to_message: nil,
sticker: nil,
supergroup_chat_created: nil,
text: "google meets",
venue: nil,
video: nil,
voice: nil
},
update_id: 412_827_321
}
# Here we are ensuring that both ways gives exactly same results
Example.sample(data) == ExampleDynamic.sample(data)
Please let me know if you have any questions.
Related documentation:
- &:maps.map/2
- &Enum.map/2
- &Map.from_struct/1
- Guards
- Map (describes specific update syntax)
12
Also Liked
idi527
![]()
Why do you want to convert these structs to maps? Maybe there’s an easier way to accomplish what you want … Personally, I don’t remember having problems with :nadia’s structs.
2
ityonemo
Still feels a bit verbose
def convert(data) when is_struct(data) do
data |> Map.from_struct |> convert
end
def convert(data) when is_map(data) do
Map.new(data, fn {k, v} -> {k, convert(v)})
end
def convert(data) when is_list(data) do
Enum.map(data, &convert/1)
end
def convert (data), do: data
2
NobbZ
You need to implement the nesting on your own. But that is a lot more expensive, as it needs to reconstruct the maps from scratch
1
Last Post!
jarlah
ok, solved with the MapFromDeepStruct which i shamelessly stole and transformed to a ListFromDeepStruct. Thing is, maps ordering are unstable. Lists not. Then i do inspect(list) and hash it
0
Popular in Questions
Hi,
I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
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
Lets say I have map like this fetching from my database
%{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
In templates/appointment/index.html.eex:
<%= for appointment <- @appointments do %>
<tr>
<td><%= appoi...
New
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
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
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
I have an umbrella app.
Some of the apps inside depend on other apps in the umbrella, unsurprisingly.
I’m writing a test for one of the...
New
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
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
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
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
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex









