Parse Request with nested JSON in phoenix

I have the following Json request

{
    "id": "4",
    "imp": [{
        "id": "1",
        "banner": {
            "w": 300,
            "h": 250,
            "mimes": [
                "image/jpg",
                "image/gif",
                "text/html",
                "image/png",
                "image/jpeg",
                "application/javascript"
            ],
            
            "hmin": 250
        }, 
        "bidfloor": 0.01,
        "bidfloorcur": "USD",
    },
    {
        "id": "2",
        "banner": {
            "w": 300,
            "h": 250,
            "mimes": [
                "image/jpg",
                "image/gif",
                "text/html",
                "image/png",
                "image/jpeg",
                "application/javascript"
            ],
            
            "hmin": 250
        }, 
        "bidfloor": 0.033,
        "bidfloorcur": "USD",
    },],
  "tmax": 2000,
}

I want to receive this json request and update some of its field and return it

I tried the following code

def index(conn, params) do
    

    if (!params) do
      Plug.Conn.send_resp(204)
    else
      IO.puts "RRR"
      params=put_in(params["tmax"], params["tmax"]- 20)
      params=put_in(Enum.at(params["imp"],0)["bidfloor"],  Enum.at(params["imp"],0)["bidfloor"]+2)

      Enum.each params["imp"], fn x -> 
        IO.inspect x
        params=put_in(x["bidfloor"],  x["bidfloor"]+20)
      end

      json(conn,  params)
    end

but this line

      params=put_in(Enum.at(params["imp"],0)["bidfloor"],  Enum.at(params["imp"],0)["bidfloor"]+2)

is only returning part of the request (the “imp” part)

what should I do?

I would probably do an Enum.map on the “imp” node and handle that list separately. Basically create a new list and replace the one that you have with Map.put. But its hard to explain but try to avoid looking for a nodes index and update that. That is not scalable

Thanks for the fast reply

I’m new to elixir could you help me how could I do this?

Something like this

# map from json
    map = %{
      "id" => "4",
      "imp" => [
        %{
          "banner" => %{
            "h" => 250,
            "hmin" => 250,
            "mimes" => ["image/jpg", "image/gif", "text/html", "image/png",
              "image/jpeg", "application/javascript"],
            "w" => 300
          },
          "bidfloor" => 0.01,
          "bidfloorcur" => "USD",
          "id" => "1"
        },
        %{
          "banner" => %{
            "h" => 250,
            "hmin" => 250,
            "mimes" => ["image/jpg", "image/gif", "text/html", "image/png",
              "image/jpeg", "application/javascript"],
            "w" => 300
          },
          "bidfloor" => 0.033,
          "bidfloorcur" => "USD",
          "id" => "2"
        }
      ],
      "tmax" => 2000
    }

# create a new imp
imp =
  Map.get(map, "imp")
  |> Enum.map(fn %{"bidfloor" => bidfloor} = node ->
    Map.put(node, "bidfloor" (bidfloor + 2))
  end)

# Add imp to the initial map
Map.put(map, "imp", imp)
2 Likes

Thanks for the amazing reply, but what if I have more levels something like this:
“imp”: [{
“bid”:[{
“bidfloor”:10
}
]
}]

ofcourse I’m having multiple “bids”

Inside

  |> Enum.map(fn %{"bidfloor" => bidfloor} = node ->
    Map.put(node, "bidfloor" (bidfloor + 2))
  end)

you will probably need to run an extra Enum.map for that nested list

However, remember that you can brake this out in smaller functions that you can give descriptive names. Otherwise its easy to get lost.

I have tried the following

imp= Map.get(body, "imp")

         |> Enum.map(fn %{"bid" => bid} = node ->

            Enum.map(node,fn %{"bidfloor" => bidfloor} = node2 ->

              Map.put(node2, "bidfloor",bidfloor - 546)

            end)

         end)

But I get the error 

```Elixir: (FunctionClauseError) no function clause matching

I think it should be Enum.map(bid, fn %{"bidfloor" => bidfloor} = node2 ->

1 Like