Repo.insert_all embed schema Ecto not working

I want to use Repo.insert_all into the database using PostgreSQL

migration file
defmodule K3.Repo.Migrations.CreateTracking do
  use Ecto.Migration
  def change do
    create table(:tracking) do
      add :odometer, :float
      add :event, :string
      add :timestamp, :string
      add :uuid, :string
      add :activity, :jsonb
      timestamps()
    end
  end
end

defmodule K3.Location.Tracking do
  use Ecto.Schema
  import Ecto.Changeset
  alias Nh24.Location.Embedded.{Activity}

  @derive {Jason.Encoder, only: [:id,:activity,:event,:odometer,:timestamp,:uuid]}
  schema "tracking" do
    embeds_one :activity, Activity
    field :event, :string
    field :odometer, :float
    field :timestamp, :string
    field :uuid, :string

    timestamps()
  end

  @doc false
  def changeset(tracking, attrs) do
    tracking
    |> cast(attrs, ~w(odometer event timestamp uuid)a)
    |> validate_required(~w(mock odometer event timestamp uuid)a)
    |> cast_embed(:activity)
  end
end

==> insert
 @test_data %{
    id: 1,
    event: "providerchange",
    uuid: "df771a85-17ea-43c6-8552-9d28c522002a",
    timestamp: "2022-07-20T03:10:21.309Z",
    odometer: 77299.3,
    activity: %{
      type: "still",
      confidence: 100
    },
   
  }
Repo.insert(Tracking,@test_data) #OK
Repo.insert_all(Tracking,[@test_data,@test_data]) #Error
 Another approach I try to update like below code
def create_bulk(multiple_attrs) do
    multiple_attrs =
      Enum.map(multiple_attrs, fn attrs ->
        attrs
        |> Map.put(:inserted_at, NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second))
        |> Map.put(:updated_at, NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second))
        |> (fn attrs ->
              %{attrs | activity: struct(Activity, attrs.activity)}
            end).()
      end)

    Repo.insert_all(Tracking, multiple_attrs)
  end

ERROR message
** (ArgumentError) cannot dump embed `activity`, expected a struct K3.Location.Embedded.Activity value but got: %{confidence: 100, type: "still"}
    (ecto 3.9.1) lib/ecto/embedded.ex:111: Ecto.Embedded.dump_field/6
    (ecto 3.9.1) lib/ecto/embedded.ex:89: Ecto.Embedded.dump/3
    (ecto 3.9.1) lib/ecto/type.ex:936: Ecto.Type.process_dumpers/3
    (ecto 3.9.1) lib/ecto/repo/schema.ex:1006: Ecto.Repo.Schema.dump_field!/6
    (ecto 3.9.1) lib/ecto/repo/schema.ex:183: Ecto.Repo.Schema.extract_value/6
    (elixir 1.14.1) lib/enum.ex:1786: anonymous fn/3 in Enum.map_reduce/3
    (stdlib 4.0) maps.erl:411: :maps.fold_1/3
    (elixir 1.14.1) lib/enum.ex:2480: Enum.map_reduce/3
    (ecto 3.9.1) lib/ecto/repo/schema.ex:87: anonymous fn/5 in Ecto.Repo.Schema.extract_header_and_fields/8
    (elixir 1.14.1) lib/enum.ex:1780: Enum."-map_reduce/3-lists^mapfoldl/2-0-"/3
    (ecto 3.9.1) lib/ecto/repo/schema.ex:86: Ecto.Repo.Schema.extract_header_and_fields/8
    (ecto 3.9.1) lib/ecto/repo/schema.ex:48: Ecto.Repo.Schema.do_insert_all/7
    iex:7: (file)

You have to use the embedded schema’s struct instead of a map, as specified in the above error.

2 Likes

thank you sir right now end up doing like this without validation

reference Doing Bulk Insertions with Embedded Schemas with Ecto.Repo.insert_all - TY

def create_bulk(multiple_attrs) do
    multiple_attrs =
      Enum.map(multiple_attrs, fn attrs ->
        attrs
        |> Map.put(:inserted_at, NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second))
        |> Map.put(:updated_at, NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second))
        |> Map.put(:activity, struct(Activity, attrs.activity))
      end)

    Repo.insert_all(Tracking, multiple_attrs)
  end