Elixir insert map in to list - Mutiple image upload in the same order

I am doing images upload.

from form, I am getting these parameters in my controller.

%{
  "description" => "Sample Product",
  "images" => [
    [
      %Plug.Upload{
        content_type: "image/jpeg",
        filename: "deuteronomy-2223-eggstransvestite-transvestism-cross-dressing-cult-prostitutes-lost-and-found-35-638.jpg",
        path: "/tmp/plug-1586/multipart-1586544497-662772098094503-1"
      }
    ],
    [
      %Plug.Upload{
        content_type: "image/png",
        filename: "Screenshot from 2020-01-23 12-53-10.png",
        path: "/tmp/plug-1586/multipart-1586544498-689460437530082-1"
      }
    ],
    [
      %Plug.Upload{
        content_type: "image/png",
        filename: "Screenshot from 2020-01-23 12-52-42.png",
        path: "/tmp/plug-1586/multipart-1586544498-797645038247073-1"
      }
    ]
  ],
  "name" => "TV"
}

Before Repo.insert operation. I need to upload the images to s3 and form a struct like below

Product Table Struct 

%{ name: "TV", description: "Sample Product"}


Product Images Table Struct

[
	%{ product_id: "#{from above inserted result}", image_name: "s3_url_1"},
	%{ product_id: "#{from above inserted result}", image_name: "s3_url_2"},
	%{ product_id: "#{from above inserted result}", image_name: "s3_url_3"}
]

Form Params

%{
  "description" => "Sample Product",
  "images" => [
    [
      %Plug.Upload{
        content_type: "image/jpeg",
        filename: "found-35-638.jpg",
        path: "/tmp/plug-1586/multipart-1586545083-172908842785287-1"
      }
    ],
    [
      %Plug.Upload{
        content_type: "image/png",
        filename: "Screenshot from 2020-01-23 12-53-10.png",
        path: "/tmp/plug-1586/multipart-1586545084-376423312372147-1"
      }
    ],
    [
      %Plug.Upload{
        content_type: "image/png",
        filename: "Screenshot from 2020-01-23 12-52-42.png",
        path: "/tmp/plug-1586/multipart-1586545084-229324763820405-1"
      }
    ]
  ],
  "name" => "TV"
}

I can easily get the product struct. For getting product image table struct first i have to upload all the images and then form a struct.

My question is

  1. when I upload images in the same order in which i am getting from form params. For ex
    “images” => [ “image_1”, “image_2”, “image_3”]. So i need to upload all the three images and store in DB in the same order.
    For ex
    Repo.insert( %{image_name: “image_1”})
    Repo.insert( %{image_name: “image_2”})
    Repo.insert( %{image_name: “image_3”})

I mean the order must not change while insert in DB. Because if image 1 is a very big one and it will take time so before image 1 insert image 2 and image 3 will be inserted. That should not happen.

    images_map      = Enum.reduce(images, [], fn x, acc ->

                          image_url = upload_to_s3(x)   #return s3 URL

                          [{:image_name, image_url} | acc]
                      end)

I am getting this output

[image_name: "s3_url", image_name: "s3_url", image_name: "s3_url"]

but I need in this format

[
	%{ image_name: "s3_url_1"},
	%{ image_name: "s3_url_2"},
	%{ image_name: "s3_url_3"}
]

Can anyone give me insight on how to achieve this? Your help is greatly appreciated.Thanks

You’re building the list of tuples here. If you want a list of maps, construct it here instead:

[%{image_name: image_url} | acc]

You’re reducing into a list instead of using say Enum.map, so you’ll also need to explicitly reverse, since reduce builds the list up backwards (which is normal).

1 Like

Can you explain this little more? thanks

You can either:

images_map = Enum.map(images, fn image ->
  image_url = upload_to_s3(x
  %{image_url: image_url}
end)

OR

backwards_images_map = Enum.reduce(images, [], fn image, acc ->
  image_url = upload_to_s3(x
  [%{image_url: image_url} | acc]
end)
images_map = Enum.reverse(backwards_images_map)

Enum.reduce builds the list from back to front, so the third item would end as the first result, so you need to reverse it if you want it in the same order as the inputs. Enum.map basically does all of that for you internally.

2 Likes