jhefreyzz

jhefreyzz

Transforming list of structs to map

Hi,
Is there an easier way to convert a list of structs to map. Extracting fields from the struct and in the nested struct and make it a map.

The list of struct:

[
  %Kaiwa.Chat.Message{
    __meta__: #Ecto.Schema.Metadata<:loaded, "messages">,
    id: 1,
    inserted_at: ~N[2020-04-03 11:46:24],
    room: #Ecto.Association.NotLoaded<association :room is not loaded>,
    room_id: 1,
    text: "this is a test message",
    updated_at: ~N[2020-04-03 11:46:24],
    user: %Kaiwa.Accounts.User{
      __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
      id: 1,
      inserted_at: ~N[2020-04-02 04:10:00],
      messages: #Ecto.Association.NotLoaded<association :messages is not loaded>,
      name: "Mr Testing",
      password: nil,
      password_hash: "$argon2id$v=19$m=131072,t=8,p=4$26a9JgOy+rmuhjQ7WZD1bg$ZJe55e9UdfrWqm0E4rMnGFG7mA/Wyr7fWdi1f1tZP+8",
      rooms: #Ecto.Association.NotLoaded<association :rooms is not loaded>,
      updated_at: ~N[2020-04-02 04:10:00],
      username: "test" 
    },
    user_id: 1
  }
] 

My attempt:

Enum.map(messages, fn message ->
  user = Map.from_struct(message.user)

  %{
    message_id: message.id,
    text: message.text,
    created_at: message.inserted_at,
    user_id: user.id,
    name: user.name
  }
end)

Expected result:

[
  %{
    created_at: ~N[2020-04-03 11:46:24],
    message_id: 1,
    name: "Mr Testing",
    text: "this is a test message", 
    user_id: 1
  }
]

Is there a better way to achieve the expected result or my attempt is okay?

Marked As Solved

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe
user_map = Map.take(user, [:name, :id, :username])

Also Liked

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

This is going to include a lot of keys you don’t want like __meta__ and password_hash (very bad). If you’re trying to create a JSON response for an API I recommend just explicitly making maps for each of the things you want to expose.

dimitarvp

dimitarvp

I would be more comfortable with something that asserts the shape of the data it receives so I can catch bugs early:

    Enum.map(
      messages,
      fn %{
           id: message_id,
           text: text,
           inserted_at: created_at,
           user: %{id: user_id, name: name}
         } ->
        %{
          message_id: message_id,
          text: text,
          created_at: created_at,
          user_id: user_id,
          name: name
        }
      end
    )

If even one message doesn’t comply with the expected structure you’ll get an appropriate error. Although to be fair, your code would also blow up but IMO in a slightly less intuitive fashion. I’d prefer mine because it also makes intent clearer.

Where Next?

Popular in Questions Top

shahryarjb
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
senggen
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
sergio
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
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
minhajuddin
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
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New

Other popular topics Top

JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
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
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
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
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
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
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New

We're in Beta

About us Mission Statement