Enum.map takes an Enumerable and a function, and maps each item in the enumerable to the result of calling the given function on it. Look close at your code here:
if y != "" && Map.has_key?(a, "id") do
a |> Enum.map(fn %{"id" => id} = node2 ->
Map.put(node2,"id",y)
end)
end
You verify if the map a has the key "id", so a is a map. When you use Enum.map on a map, the elements being iterated are {key, value} tuples, so they definitely won’t match %{"id" => id}, hence the error.
My recommendation is to first unnest your code and split it into smaller functions. This will make it a lot easier to follow, test, and debug.
This will still iterate over a list of key-value-pairs.
Calling any function from Enum is semantically equivalent to calling enumerable |> Enum.into([]) |> your_function_call.
And as any map (the datastructuire) can only have a single "id" key, you do not need to Enum.map over the map, but you can instead use Map.update(!) to change the value.
Well, Map.update/4 (or Map.update!/3) does not work that way: it expects an update function that receives the value and computes the new value:
a = %{"x" => 1}
# Say we want to increment the value associated to "x" by 1:
Map.update(a, "x", 0, fn value ->
value + 1
end)
Also, I suspect you might be misunderstanding how Elixir data structures work. Functions like Map.put(...) or Map.update(...) return a modified copy of the original map. They do not mutate the original map. This is a very important core concept about Elixir: all data structures are immutable.
So, for example:
a = %{ "one" => 1, "two" => 2 }
# This returns a new map, with the new "three" key set to 3
Map.put(a, "three", 3)
#=> %{ "one" => 1, "two" => 2, "three" => 3 }
# But the old map is still unchanged:
a
#=> %{ "one" => 1, "two" => 2 }
I suggest you take your time to understand how to work with immutable data structures, everything will be much clearer afterwards.
I took a stab at making this a little more idiomatic. I found it a bit difficult to follow the logic but structurally you can remove a lot of the code by stronger pattern matching and by decomposing into functions with multiple heads. Here is my quick attempt to demonstrate:
def transform(%{"a" => %{"bdl" => bdl} = a, "i" => i} = b) do
Enum.map(i, fn %{"ban" => %{"w" => w, "h" => h}} = node ->
key = "#{d}-#{bdl}-ban-#{w}-#{h}"
if tag = get(key) do
transform_node(node, tag, a)
else
node
end
end)
end
# "y" is ""
def transform_node(node, %{"y" => "", "z" => z} = tag, _a) do
Map.put(node, "t", z)
end
# Since you are checking if a has the key "id" then there can only be one
# "id" key and therefore Enum isn't useful - just update
def transform_node(node, %{"x" => x, "y" => y, "z" => z} = tag, %{"id" => id} = a) do
# Logic not clear to me what really happens here
end
# a has no key "id"
def transform_node(node, %{"z" => z}, _a) do
Map.put(node, "t", z)
end