将某些变更集字段转换为ecto:map字段

时间:2018-11-03 00:11:21

标签: elixir ecto single-table-inheritance

我有一个如下所示的变更集:

%{
  creator_id: "4",
  name: "a test with GraphQL",
  place_id: "13",
  entree_id: "8",
  base: "wheat",
  type: "food"
}

我的ecto模式如下:

schema "items" do
  field :type, :string
  field :name, :string
  field :data, :map

  belongs_to :creator, Name.SubName.Creators
  belongs_to :place,   Name.SubName.Places
  belongs_to :entree,  Name.SubName.Entrees

  timestamps()
end

如您所见,base不是ecto模式中的字段,我想将base强制转换为data字段,使其成为{{1} }类型,即map。我在这里使用某种形式的单表继承。

我正在尝试将记录添加到我的{"base":"wheat"}表中。现在,当我从表中读取数据时,我将items字段强制转换为包含我的data字段的嵌入模式(取决于type)。我要努力的是将这个字段返回数据库。

我尝试使用类似base的方法,但是很显然,它只是获得了显然不是有效映射的值。另外,为与代表每个Ecto.Changeset.cast(params[:base], Map.keys(%{data: :map}))的其他嵌入式模式相关联的所有唯一字段指定字段会很麻烦。

typeembeds_one不适用于这种情况,因为embeds_many ecto字段表示不同的嵌入式架构类型。因此,在这种情况下,我的问题不是关于嵌入式模式的使用,而是关于在data中挑选特定字段并将其转换为changeset的问题。一半的人只是认为我应该为每个map做一个不同的表,然后我不必为此担心。

1 个答案:

答案 0 :(得分:1)

您可以使用Map.split/2

@required_fields [:name, :type, :creator_id, :place_id, :entree_id]
@all_fields [:data | @required_fields]

def changeset(struct, params) do
  {allowed, others} = Map.split(params, @required_fields)
  params = Map.put(allowed, :data, others)

  struct
  |> cast(params, @all_fields)
  |> # ...
end

这里要注意的重要一点是,该示例仅适用于具有原子键的映射,您必须对其进行一些修改才能与字符串键和原子键一起使用。您还可以考虑将一个空映射指定为:data的默认值。