Я хочу хранить данные с помощью jsonb, который может быть либо массивом, либо картой. Исходные данные поступают либо в виде массива, либо в виде карты, и мы хотим унифицировать их на сервере, чтобы интерфейс мог работать с одним типом. Есть ли способ/обходной путь, который я могу использовать, хранить и извлекать как типы json/map, так и массивы, которые действительны для типа jsonb postgres?
Я пытался использовать source:
для копирования в поле типа массива sourced
перед вызовом конвейера приведения, если я получаю массив в params
:
condition: Map.has_key?(params, "value") && is_list(value)
Я успешно могу сохранить данные, но при извлечении из БД я получаю ошибку приведения
field(:value, :map)
field(:value_array, {:array, :integer}, source: :value)
Примечание. Версия Ecto > 3 и postgres 10
Решение состояло в том, чтобы определить пользовательские типы экто, который будет принимать и загружать как массивы, так и карты.
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
Кредит достается идиот - пользователь elixirforum