Ecto :map vs :embeds_one

Hello,

What is the difference between:

defmodule User do
  use Ecto.Schema
  schema "users" do
    field :name, :string
    embeds_one :phones, Phone
  end
end

defmodule Phone do
  use Ecto.Schema
  embedded_schema do
    field :number, :string
    field :country, :string
  end
end

and

defmodule User do
  use Ecto.Schema
  schema "users" do
    field :name, :string
    field :phones, :map
  end
end

In other words, what does the use of embeds_one with the embedded_schema allows me to do that I can’t by just defining a :map type in the schema?

2 Likes

:wave:

It provides some semblance of structure into your json.

With embeds_one, ecto will cast the data into a struct and also give it an ID (more useful for collections). With a map, it stays a map. One consequence is that structs have atom keys, whereas the map will have string keys (because of JSON serialization). A struct always has the same keys, whereas a map can have arbitrary keys. It is harder to use changesets on plain maps, because you must also specify the types of each field.

4 Likes

It’s possible to use @primary_key false on embedded schemas as well. But then the embeds_one macro would need to have :on_update option set. It’s useful when upgrading from plain maps to embeds.

1 Like

Darn! this saved me hours! Not all heroes wear capes. I bow before you.