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
Popular in Questions
In Ruby, I can go:
User.find_by(email: "foobar@email.com").update(email: "hello@email.com")
How can I do something similar in Elixir?
...
New
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
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
Hello, I have map which I want to convert it to string like this:
the map:
%{last_name: "tavakkoli", name: "shahryar"}
the string I ne...
New
Hello, I get Persian date from my client and convert it to normal calendar like this:
def jalali_string_to_miladi_english_number(persi...
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
I’m trying to make a websocket server in Phoenix or raw Elixir. I heard about gun, I think I could use cowboy, but since I’m not that sma...
New
I will often find my self writing things similar to:
case some_value do
nil -> something()
"" -> something()
_ -> somethi...
New
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
Other popular topics
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
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1]
15:22:35.803 [error] gen_event {lager_file_backend...
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
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
What is the idiomatic way of matching for not nil in Elixir?
E.g.,
First way:
defp halt_if_not_signed_in(conn, signed_in_account) when...
New
Hello guys,
I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
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
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
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








