Embed a struct in a virtual field

I have a schema that has metrics that are not stored in the DB but computed later.

schema entity do
  field :metrics, {:array, :map}, virtual: true, default: nil)

The metric is a struct like this:

%Metric{start: date_time, stop: date_time, error_rate: float}

Can I somehow indicate in the schema that metrics will always have those three fields?
I like exploring codebase by its data structures.
If I stumble upon something like {:array, :map} I can’t see what struct is that. The compiler also doesn’t check if I use correct keys when I access metrics because they are free form maps.
Unfortunately virtual: true does not work with has_many or embeds_many. Defining custom type with all the logic of casting to DB format also seems like overkill. Do you have a better way of embedding structs as virtual fields in the schema?


If the type is only used virtually, you might get away with defining a custom type where actually load and dump are error-throwing no-ops, and only cast is implemented in a sensible way (like calling struct!/2).

1 Like

I have a project that use embeds_many

Hope it will help

alias Connect.Campaign.Starting

schema "campaigns" do
    field :description, :string

    embeds_many :startings, Starting


defmodule Connect.Campaign.Starting do
  use Ecto.Schema
  import Ecto.Changeset
  alias Connect.Campaign.Starting

  embedded_schema do
    field :can_run, :boolean, default: true
    field :day, :integer, default: 0
    field :end_at, :time, default: ~T[20:00:00]
    field :start_at, :time, default: ~T[08:00:00]


Adjust it to your needs

1 Like

Thank you for your input.
Unfortunately, that solution persists :startings in the DB. I’d like not to persist it but virtual: true does not mix with embeds_many.

1 Like

If I’m not mistaken, you can still use an embedded_schema without saving it to the database. Just don’t cast the field nor make it required when you generate changesets.

I had a similar problem this week, you might want to take a look at this topic: