使用ecto存储自定义信息
Using ecto to store custom information
我正在 Phoenix 重新实现我最初在 Rails 中编写的应用程序,用户可以在其中使用 PostgreSQL 的 JSONB 记录类型创建自定义字段。例如,我们有以下(简化表示)模式:
客户
- ID(整数)
- 客户端类型 ID(整数)
- 姓名(字符串)
- 信息 (jsonb)
客户类型
- ID(整数)
- 姓名(字符串)
自定义字段定义
- ID(整数)
- 客户端类型 ID(整数)
- 键(字符串)
- 标签(字符串)
在 Rails 中,ActiveRecord 神奇地将 JSONB 与哈希相互转换,这使我可以使用 JSONB 非常轻松地存储一组无模式的自定义字段。
例如,每个客户端类型可以定义不同的自定义字段,然后当我向用户显示信息时,我循环遍历定义以获取键,然后使用这些键从 JSONB 中获取数据文件.
我试图找出一种使用 Ecto 完成此操作的方法,看起来我应该查看嵌入式模式(我看到了一些有用的信息 here),但我不认为通过查看它,我可以在 运行 时为此定义自定义数量的字段,可以吗?
我只是在寻求一些建议,因为到目前为止,这是我遇到的唯一一个几乎没有立即解决的真正障碍。
再次感谢,非常感谢!
Postgrex 有一个 example for a JSON extension in its Readme,它应该完全符合您的要求。
我可以通过稍微更改我的数据结构来解决这个问题。自定义字段现在是一个 JSONB 数组,它允许我做一个非常优雅的 embeds_many 关系。实际上,我还没有足够仔细地阅读 link (http://blog.plataformatec.com.br/2015/08/working-with-ecto-associations-and-embeds/) 上的文档,在阅读之后我意识到我的数据结构化程度不够。
所以,不用像
这样的 JSONB 列
{
"name":"Something",
"address":"123 Fake St"
}
看起来像
[
{
"field":"name",
"value":"Something"
},
{
"field":"address",
"value":"123 Fake St"
},
]
这似乎是我用例的最佳选择,但它确实占用了更多空间 space(因为 Ecto 在幕后为每个对象添加了一个必需的 ID 字段以确保完整性)。
更改为此结构后,我简单地创建了一个模型并根据 link 将它们关联起来。简而言之,它看起来像这样:
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
我正在 Phoenix 重新实现我最初在 Rails 中编写的应用程序,用户可以在其中使用 PostgreSQL 的 JSONB 记录类型创建自定义字段。例如,我们有以下(简化表示)模式:
客户
- ID(整数)
- 客户端类型 ID(整数)
- 姓名(字符串)
- 信息 (jsonb)
客户类型
- ID(整数)
- 姓名(字符串)
自定义字段定义
- ID(整数)
- 客户端类型 ID(整数)
- 键(字符串)
- 标签(字符串)
在 Rails 中,ActiveRecord 神奇地将 JSONB 与哈希相互转换,这使我可以使用 JSONB 非常轻松地存储一组无模式的自定义字段。
例如,每个客户端类型可以定义不同的自定义字段,然后当我向用户显示信息时,我循环遍历定义以获取键,然后使用这些键从 JSONB 中获取数据文件.
我试图找出一种使用 Ecto 完成此操作的方法,看起来我应该查看嵌入式模式(我看到了一些有用的信息 here),但我不认为通过查看它,我可以在 运行 时为此定义自定义数量的字段,可以吗?
我只是在寻求一些建议,因为到目前为止,这是我遇到的唯一一个几乎没有立即解决的真正障碍。
再次感谢,非常感谢!
Postgrex 有一个 example for a JSON extension in its Readme,它应该完全符合您的要求。
我可以通过稍微更改我的数据结构来解决这个问题。自定义字段现在是一个 JSONB 数组,它允许我做一个非常优雅的 embeds_many 关系。实际上,我还没有足够仔细地阅读 link (http://blog.plataformatec.com.br/2015/08/working-with-ecto-associations-and-embeds/) 上的文档,在阅读之后我意识到我的数据结构化程度不够。
所以,不用像
这样的 JSONB 列{
"name":"Something",
"address":"123 Fake St"
}
看起来像
[
{
"field":"name",
"value":"Something"
},
{
"field":"address",
"value":"123 Fake St"
},
]
这似乎是我用例的最佳选择,但它确实占用了更多空间 space(因为 Ecto 在幕后为每个对象添加了一个必需的 ID 字段以确保完整性)。
更改为此结构后,我简单地创建了一个模型并根据 link 将它们关联起来。简而言之,它看起来像这样:
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