Convert Map to JSON when saving to database?

I’ve got an Ecto schema that has a column where I store some random data from a 3rd-party provider. This is mostly just for book-keeping purposes so we can search/parse it later if needed. In the database, this meta column is defined as a string. In my code, I end up with a Map which represents the data that I wish to store.

My question is: what’s the most elegant way to convert the Map to JSON on the way into the database and convert it back into a map on the way out? Could this accomplished via a custom Ecto.Type (I think yes)? Or should it be handled via some other means?

Thanks for recommendations/thoughts!

1 Like

If you’re using postgres I’d recommend storing the field as jsonb in the database instead of a string, then if you have a field :metadata, :map ecto will handle the serialization for you (and you can even query and index directly on fields inside the jsonb column)

3 Likes

Just to be thorough for future visitors, here’s the full example:

From my migration:

# ...
# (The :map type gets mapped to :jsonb for PostGres from what I understand)
add :meta, :map, default: "{}"  # <-- assuming I always want to store a JSON object

From my schema:

# ...
field :meta, :map, null: false, default: "{}"

And how it all works:

attrs = %{
    # ...
    meta: %{
        arbitrary: "stuff"
    }
}
result = %MyThing{}
  |> MyThing.changeset(attrs)
  |> Repo.insert()

  # result:
  %Auth.Schemas.AuthorityUser{
      __meta__: #Ecto.Schema.Metadata<:loaded,"my_thing">,
      # ...
      meta: %{
          "arbitrary" => "stuff",
      },
     # ...
  }
4 Likes

I believe that in your migration file(s) and schema module(s) you can replace the "{}" string literal with a map literal: %{}.

1 Like