私はPostgresに一連の座標([[x1,y1], [x2,y2]]
)を保存したいとします。望ましいデータ型は何ですか?ドキュメントでは、配列はEctoスキーマに多次元配列を格納する方法は?
:coordinates, {:array, :float}
という形で指定できますが、これは1次元配列に対してのみ有効です。
私はPostgresに一連の座標([[x1,y1], [x2,y2]]
)を保存したいとします。望ましいデータ型は何ですか?ドキュメントでは、配列はEctoスキーマに多次元配列を格納する方法は?
:coordinates, {:array, :float}
という形で指定できますが、これは1次元配列に対してのみ有効です。
あなたは
field :coordinates, {:array, {:array, :float}}
を使用することができますが、それは最善の解決策ではありません。悪く見えて、このようなものがデータベースに挿入されることを許可します。これは明らかに座標ではありません。私はカスタムタイプを好むだろう。
#lib/coordinates.ex
defmodule Coordinates do
@behaviour Ecto.Type
def type, do: {:array, :float}
def cast([l1, l2] = coordinates) when is_list(l1) and length(l1) == 2 and is_list(l2) and length(l2) == 2 do
flattened_list = coordinates |> List.flatten
cond do
Enum.all?(flattened_list, &(is_float(&1))) ->
{:ok, list}
# add additional [integer, string, ...] to float transformations here if necessary
# Enum.all?(flattened_list, &(is_float(&1) || is_integer(&1))) ->
# normalized = flattened_list |> Enum.map(&(&1/1)) |> Enum.split(2) |> Tuple.to_list
#
# {:ok, normalized}
true ->
:error
end
end
def cast(_), do: :error
def load(list) when is_list(list) and length(list) == 4 do
two_dimensional_list = list |> Enum.split(2) |> Tuple.to_list
{:ok, two_dimensional_list}
end
def dump(list) when is_list(list) and length(list) == 2 do
flattened_list = coordinates |> List.flatten
{:ok, flattened_list}
end
def dump(_), do: :error
end
#web/models/your_model.ex
schema "your_model" do
field :coordinates, Coordinates
end
文書によると、Ecto.Typeのふるまいは、4つの機能が実装されることを期待しています。
タイプは出力DBタイプの名前は
:タイプと出力は、DBのタイプの例の中で最も重要な
キャストはDBタイプと出力カスタムエクトタイプ
ダンプカスタムエクトを受けるべきで受信する必要があるタイプと出力カスタムエクトタイプ
負荷を受けるべきである必要があります
は、上記のダンプとロード(1および2次元のリストの間の変換)と警備員の多く(エラー無効なデータが返されることを確認してください)です
全文を読むことをお勧めしますEcto.Type
ドキュメント: https://hexdocs.pm/ecto/Ecto.Type.html
非常に役に立ちます。
ありがとうございました。簡単にするために、移行型 '{:array、:float} 'で' field:coordinates、{:array、{:array、:float}} 'を使用して終了しました。 (リストは可変長にすることができるので、カスタムタイプのコードはより複雑になります...そして、締め切りの締め切りがあります。 –