Adding key value pair in a nested map dynamically

I have this map:

               %{
                 "$include" => %{
                    "hospitals" => %{
                       "$include" => %{"rooms" => %{"beds" => %{}}},
                       "$order" => %{"id" => "$asc"}
                    },
                   "doctors" => %{
                       "$order" => %{"id" => "$desc"}                      
                    }
                 }
              }

There is any number of $include statements nested inside $include. so it should be dynamic. The output should be.

               %{
                 "$include" => %{
                    "hospitals" => %{
                       "$include" => %{"rooms" => %{"beds" => %{"binding" => "last"}, "binding" => "last"}},
                       "$order" => %{"id" => "$asc"},
                       "binding" => "first"
                    },
                   "doctors" => %{
                       "$order" => %{"id" => "$desc"},
                       "binding" => "first"
                    }
                 }
              }

All the outer maps should include binding => "first" and all nested include should contain "binding "=> "last".

Any help will be much appreciated.

Thanks

@script Try this one:

defmodule Example do
  def sample(map) when is_map(map), do: map(map, false)

  defp do_sample(_key, value, _nested) when not is_map(value), do: value

  defp do_sample("$" <> _key, value, nested), do: map(value, nested)

  defp do_sample(_key, value, nested), do: value |> map(true) |> put_binding(nested)

  defp map(map, nested), do: :maps.map(&do_sample(&1, &2, nested), map)

  defp put_binding(map, false), do: Map.put_new(map, "binding", "first")
  defp put_binding(map, true), do: Map.put_new(map, "binding", "last")
end

Helpful resources:

  1. Map.put_new/3
  2. :maps.map/2
3 Likes

thanks a lot for your help. Can you please tweak it a little bit to support params which are not maps like this:

       "$include" => %{
         "fat_hospitals" => %{
           "$join" => "$full"
        }

it’s throwing error for join.

Also if the nested include is a list or a string like this:

                      opts = %{
                              "$include" => %{"hospitals" => %{"$include" => ["rooms"]}}
                               }

it should be like this:

                         opts = %{
                          "$include" => %{"hospitals" => %{"$include" => ["rooms"], "$binding" => "last"}}
                           }

Thanks again.

There is also get_and_update_in which can be helpful.

4 Likes

I have updated my response. Do you expect maps in lists too?

No just lists of strings or simple strings like this:

“$include” => “rooms”.

include contain three types of data structures:

“$include” -> %{}
“$include” -> [“rooms”, “beds”]
“$include” -> “beds”

Thanks again for your help and time.

1 Like