如何序列化 Ecto 记录结构以使其可存储为数据库中的 :map?
How to serialize Ecto record struct to make it storeable as :map in the database?
我想存储从 Repo.get(MyModel, id)
返回的 Ecto.Schema
结构。
像__meta__
、association: <Association is not loaded>
这样的东西阻止了它的jsonifying,所以我捕获了一个异常(这是合理的)。是否有任何 Ecto
本机函数只获取我可以序列化并存储在数据库中的记录列映射?
因为我不知道任何用于此目的的 Ecto 本机函数,我想你应该使用:
https://hexdocs.pm/elixir/Map.html#from_struct/1
过滤您不需要的键:
https://hexdocs.pm/elixir/Enum.html#filter/2
并将结果设置为:
https://hexdocs.pm/elixir/Enum.html#into/2
编辑:看起来您可以在查询中使用 "map()" 来 return 映射而不是结构:https://github.com/elixir-ecto/ecto/issues/1348
我的解决方案
defmodule MyApp.Schema do
@schema_meta_fields [:__meta__]
def to_storeable_map(struct) do
association_fields = struct.__struct__.__schema__(:associations)
waste_fields = association_fields ++ @schema_meta_fields
struct |> Map.from_struct |> Map.drop(waste_fields)
end
end
Elixir 允许您导出 协议实现:Kernel.defstruct/1
我不确定您使用的是什么 JSON 解析器,但是对于 Jason
,例如,您可以在他们的自述文件中找到以下内容:
If you need to encode some struct that does not implement the protocol, if you own the struct, you can derive the implementation specifying which fields should be encoded to JSON:
@derive {Jason.Encoder, only: [....]}
defstruct # ...
Finally, if you don't own the struct you want to encode to JSON, you may use Protocol.derive/3 placed outside of any module:
Protocol.derive(Jason.Encoder, NameOfTheStruct, only: [...])
Protocol.derive(Jason.Encoder, NameOfTheStruct)
不妨也展示一下如何使用 Poison:
When deriving structs for encoding, it is possible to select or exclude specific attributes. This is achieved by deriving Poison.Encoder with the :only or :except options set:
defmodule PersonOnlyName do
@derive {Poison.Encoder, only: [:name]}
defstruct [:name, :age]
end
defmodule PersonWithoutName do
@derive {Poison.Encoder, except: [:name]}
defstruct [:name, :age]
end
In case both :only and :except keys are defined, the :except option is ignored.
我想存储从 Repo.get(MyModel, id)
返回的 Ecto.Schema
结构。
像__meta__
、association: <Association is not loaded>
这样的东西阻止了它的jsonifying,所以我捕获了一个异常(这是合理的)。是否有任何 Ecto
本机函数只获取我可以序列化并存储在数据库中的记录列映射?
因为我不知道任何用于此目的的 Ecto 本机函数,我想你应该使用:
https://hexdocs.pm/elixir/Map.html#from_struct/1
过滤您不需要的键:
https://hexdocs.pm/elixir/Enum.html#filter/2
并将结果设置为:
https://hexdocs.pm/elixir/Enum.html#into/2
编辑:看起来您可以在查询中使用 "map()" 来 return 映射而不是结构:https://github.com/elixir-ecto/ecto/issues/1348
我的解决方案
defmodule MyApp.Schema do
@schema_meta_fields [:__meta__]
def to_storeable_map(struct) do
association_fields = struct.__struct__.__schema__(:associations)
waste_fields = association_fields ++ @schema_meta_fields
struct |> Map.from_struct |> Map.drop(waste_fields)
end
end
Elixir 允许您导出 协议实现:Kernel.defstruct/1
我不确定您使用的是什么 JSON 解析器,但是对于 Jason
,例如,您可以在他们的自述文件中找到以下内容:
If you need to encode some struct that does not implement the protocol, if you own the struct, you can derive the implementation specifying which fields should be encoded to JSON:
@derive {Jason.Encoder, only: [....]}
defstruct # ...
Finally, if you don't own the struct you want to encode to JSON, you may use Protocol.derive/3 placed outside of any module:
Protocol.derive(Jason.Encoder, NameOfTheStruct, only: [...])
Protocol.derive(Jason.Encoder, NameOfTheStruct)
不妨也展示一下如何使用 Poison:
When deriving structs for encoding, it is possible to select or exclude specific attributes. This is achieved by deriving Poison.Encoder with the :only or :except options set:
defmodule PersonOnlyName do
@derive {Poison.Encoder, only: [:name]}
defstruct [:name, :age]
end
defmodule PersonWithoutName do
@derive {Poison.Encoder, except: [:name]}
defstruct [:name, :age]
end
In case both :only and :except keys are defined, the :except option is ignored.