使用ecto存储自定义信息

Myl*_*lly 5 elixir ecto phoenix-framework

我正在重新实现我最初在 Phoenix 的 Rails 中编写的应用程序,其中用户可以使用 PostgreSQL 的 JSONB 记录类型创建自定义字段。例如,我们有以下(简化表示)模式:

客户

  • 身份证(整数)
  • 客户端类型 ID (int)
  • 名称(字符串)
  • 信息 (jsonb)

客户类型

  • 身份证(整数)
  • 名称(字符串)

自定义字段定义

  • 身份证(整数)
  • 客户端类型 ID (int)
  • 键(字符串)
  • 标签(字符串)

在 Rails 中,ActiveRecord 神奇地在 JSONB 和哈希之间转换,这使我可以使用 JSONB 非常轻松地存储一组无模式的自定义字段。

例如,每个客户端类型都可以定义不同的自定义字段,然后当我向用户显示信息时,我会遍历定义以获取键,然后我使用它从 JSONB 文档中获取数据。

我试图找出一种使用 Ecto 完成此操作的方法,看起来我应该查看嵌入式模式(我在这里看到了一些不错的信息),但是我认为通过查看它我无法定义一个在运行时自定义字段数量,可以吗?

我只是想就此寻求一些建议,因为到目前为止,这是我遇到的唯一一个几乎没有立即解决的真正障碍。

再次感谢,我很感激!

Myl*_*lly 2

我能够通过稍微改变我的数据结构来解决这个问题。自定义字段现在是一个 JSONB 数组,它允许我建立一个非常优雅的 embeds_many 关系。实际上,我还没有足够仔细地阅读链接(http://blog.plataformatec.com.br/2015/08/working-with-ecto-associations-and-embeds/)上的文档,在我读完之后,我意识到我的数据的结构化程度还不够。

因此,不要使用看起来像这样的 JSONB 列

{
  "name":"Something",
  "address":"123 Fake St"
}
Run Code Online (Sandbox Code Playgroud)

看起来像

[
  {
    "field":"name",
    "value":"Something"
  },
  {
    "field":"address",
    "value":"123 Fake St"
  },
]
Run Code Online (Sandbox Code Playgroud)

这似乎是我的用例的最佳选择,但它确实占用了更多空间(因为 Ecto 在幕后向每个对象添加了必需的 ID 字段以确保完整性)。

更改为此结构后,我只需创建一个模型并根据链接将它们关联起来。简而言之,它看起来像这样:

defmodule UserManager.CustomField do
  use Ecto.Model

  embedded_schema do
    field :field
    field :value
  end

  @required_fields ~w(field value)
  @optional_fields ~w()

  @doc """
  Creates a changeset based on the `model` and `params`.

  If no params are provided, an invalid changeset is returned
  with no validation performed.
  """
  def changeset(model, params \\ :empty) do
    model |> cast(params, @required_fields, @optional_fields)
  end
end

defmodule UserManager.Client do
  # ...
  schema "clients" do
    # ...
    embeds_many :custom_fields, UserManager.CustomField
    # ...
  end
  # ...
end
Run Code Online (Sandbox Code Playgroud)

  • 在这种情况下,您将如何处理不同的数据类型?假设我有一些值是布尔值,其他值是整数 (3认同)