如何在Ecto架构中存储多维数组?

时间:2016-09-10 22:39:16

标签: elixir ecto

假设我希望将一组坐标([[x1,y1], [x2,y2]])存储到Postgres中。什么是首选数据类型?文档允许以

形式的数组
:coordinates, {:array, :float}

但这只适用于一维数组。

1 个答案:

答案 0 :(得分:4)

您可以使用

plot_ly(df, lon = lon, lat = lat, text = hover, size = aggregate(df$pop,by=list(df$q),sqrt)$x,
        #marker = list(size = sqrt(pop/10000) + 1, line = list(width = 0)),
        color = q, colors= colors_wanted, type = 'scattergeo', locationmode = 'USA-states') %>%
  layout(title = '2014 US city populations<br>(Click legend to toggle)', geo= g)

但这不是最好的解决方案。看起来很糟糕,允许将这样的field :coordinates, {:array, {:array, :float}} 插入到数据库中,这显然不是坐标。我更喜欢自定义类型。

[[1.0]]

根据文档Ecto.Type行为需要实现4个函数。

  

类型应输出DB类型的名称
  演员应该接收任何类型并输出您的自定义Ecto类型
  load应该接收DB类型并输出您的自定义Ecto类型
  dump应该接收您的自定义Ecto类型并输出数据库类型

上面例子中最重要的是转储和加载(一维和二维列表之间的转换)和许多防护(确保无效数据将返回:错误)

我建议阅读完整的#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 文档: https://hexdocs.pm/ecto/Ecto.Type.html
这非常有帮助。