Need help with making an Enum/Map function to output a certain way

I’m a little newbish with the way enum and logic works with Elixir, so I need a little help here. I have a simple script that sends out a notification and Phoenix receives the following map example:

%{"action" => "newMessage", "userList" => [1,45,98], "muted" => [0,0,1], "optionalData" => ""}

What I need to do is broadcast a separate “newMessage” event to each of the three users in the userList array. I also sent a muted array, which is the user’s corresponding status for muting notifications. In the example above, only user 98 has the muted status selected.

  def notification(conn, %{"action" => _action, "userlist" => userlist, "muted" => muted, "optionalData" => _data} = payloadIn) do
    payloadOut = Map.take(payloadIn, ["action", "optionalData"])
    Enum.each(userlist, & AppWeb.Endpoint.broadcast("user:" <> &1, "newMessage", %{"payload" => payloadOut, "muted" => muted[Enum.find_index(userlist, fn x -> x == &1 end)]))
    json(conn, %{})
  end

My intended broadcasts would be something like:

Sent to user 1: %{"payload" => payloadOut, "muted" => 0}
Sent to user 45: %{"payload" => payloadOut, "muted" => 0}
Sent to user 98: %{"payload" => payloadOut, "muted" => 1}

payloadOut will be the same for each user, it will just be:

%{"action" => "newMessage", "optionalData" => data}

I don’t want to send the full userList and muted array back to users to protect the privacy of the users, from eachother, keep their muted status private, who the notifications are going out to, etc. This is why I need to send the muted status of each individual user and then the client-side javascript will handle it.

I’m getting tripped up on this part: muted[Enum.find_index(userlist, fn x -> x == &1 end)] , I get the following error, I think because array selection of muted[0] (the muted status for the first user) doesn’t work in Elixir the way it does in Javascript or PHP:

(ArgumentError) the Access calls for keywords expect the key to be an atom, got: 0

Since I’m sort of newish on Elixir programming, I was wondering if maybe there is a better way or some functions that I don’t know that might handle the logic of problem more efficiently.

Thanks

Probably the Enum.zip/2 can help:

You can do something like this:

def notification(conn, %{"action" => _action, "userlist" => userlist, "muted" => muted, "optionalData" => _data} = payloadIn) do

Enum.zip(userlist, muted)
|> Enum.map(fn {u, m} ->  
   AppWeb.Endpoint.broadcast("user:" <> u, "newMessage", %{"payload" => payloadOut, "muted" => m})
end)

Consider this a starting point, I don’t understand completely what you need.

4 Likes

Wow, that’s pretty amazing. The more I’m able to learn how to use these functions correctly and when to use them, the more I’m realizing how powerful and elegant Elixir really is. Great stuff, Thanks!

1 Like