Embedded schema and JSONB

This is an example from one of the very useful “FullstackPhoenix” tutorials, namely:

# lib/tutorial/shop/data.ex
defmodule Tutorial.Shop.Data do
  use Ecto.Schema
  import Ecto.Changeset

  @primary_key false
  embedded_schema do
    field :size, :string
    field :color, :string
  end

  @doc false
  def changeset(option, attrs) do
    option
    |> cast(attrs, [:size, :color])
    |> validate_required([])
  end
end

When saving the record, which embeds_one of the above, the whole “embedded_schema” gets stored, including fields, which are not set. This seems to make sense to me. At least as default behaviour. Out of curiosity – the question: is there a switch/option/other simple method, which would make it store only the fields, which are actually used/set?

How do you determine if a field is unset or set to be empty?

Good question. When I don’t set it, it writes nil into the field. The same would happen if I chose to set it to "". So maybe what I am thinking about is more like “don’t write empty / unset fields”. The reason for asking is more a curiosity than necessity, although I imagine that if something is set only on very rare occasions, like once in thousands of records, then simply not storing it would be more effective.

Structs in elixir have fixed keys. Those keys need to have some value and it’ll default to nil unless customized.

Right. I guess this is the answer as it probably wouldn’t be worth the effort to handle some special cases for structs, which then end up as maps stored as JSON.

You could write a custom Ecto type which only stores fields which are not nil. The wire protocol is forgiving. Your custom type can have a type of :map. In dump/1 you can emit a trimmed-down Map.

https://hexdocs.pm/ecto/Ecto.Type.html

1 Like

I don’t think it’s worth the effort in the case I have at hand. Was curious if somebody thought of such scenario and maybe provided an option OOB. But yes, if dumping whole maps becomes an issue then such custom type might help, TNX.