I want to store data using jsonb that could be either an array or a map. The source data arrives as either an array or a map, and we want to unify this on the server so the front-end can work with a single type. Is there a way/workaround that I can use, store and retrieve both json/map and array types which are valid for the jsonb postgres type?
I have tried to use source:
to copy to array type sourced
field before calling cast pipeline if I get an array in params
:
condition: Map.has_key?(params, "value") && is_list(value)
I am successfully able to save data, but when retrieving from the DB I am getting a cast error
field(:value, :map)
field(:value_array, {:array, :integer}, source: :value)
Note: Ecto version > 3 and postgres 10
Solution was to define custom ecto types which would accept and load both arrays and maps
defmodule HaiData.Jsonb do
@behaviour Ecto.Type
def type, do: :map
# Provide custom casting rules.
def cast(data) when is_list(data) or is_map(data) do
{:ok, data}
end
# Everything else is a failure though
def cast(_), do: :error
# When loading data from the database, we are guaranteed to
# receive a map or list
def load(data) when is_list(data) or is_map(data) do
{:ok, data}
end
# When dumping data to the database, we *expect* a map or list
# so we need to guard against them.
def dump(data) when is_list(data) or is_map(data), do: {:ok, data}
def dump(_), do: :error
end
Credit goes to idiot - an elixirforum user