我有一个功能:
def listAll(dataSchema, fields) do
dataSchema |> order() |> Repo.all()
end
返回如下所示的查询结果:
[%Skeleton.Data.Evento{__meta__: #Ecto.Schema.Metadata<:loaded, "eventos">,
date: "dewfwef", date_de: nil, date_es: nil, date_fr: nil, date_pt: nil,
id: nil, inserted_at: nil, text: "hello", text_de: nil,
text_es: nil, text_fr: "Bonjour", text_pt: "Olá", title: "Good morning", title_de: nil, title_es: nil, title_fr: nil, title_pt: "Bom dia"},
%Skeleton.Data.Evento{__meta__: #Ecto.Schema.Metadata<:loaded, "eventos">,
date: "ds", date_de: nil, date_es: nil, date_fr: nil, date_pt: nil, id: nil,
inserted_at: nil, text: "Bye", text_de: nil, text_es: nil,
text_fr: nil, text_pt: "Adeus", title: "Good evening", title_de: nil, title_es: nil, title_fr: nil, title_pt: "Boa noite"}]
fields
是一个包含任意数量键的列表:
fields = [:date_pt, :text_pt, :title_pt]
如何将date, text, title
的所有值(相同的键名但没有后缀)替换为text_pt
的值(或fields
参数中传递的任何键/键) ?
请注意,我们不知道我们拥有哪些密钥,因为它们作为参数在个案情况下传递,并且我希望在Ecto查询中执行此操作,而不是在结果的结构列表中执行此操作。
答案 0 :(得分:1)
以下是我如何执行此操作,假设字段包含带有字符串的locale
键,例如"pt"
:
def listAll(dataSchema, %{locale: locale}) do
text_field = :"text_#{locale}"
dataSchema
|> select([m], %{m | text: field(m, ^text_field)})
|> order()
|> Repo.all()
end
这会将text
的值替换为动态计算字段text_field
的值。
注意:您应确保使用白名单在某个时刻验证locale
。如果用户可以发送任意区域设置,则创建该原子可能会导致VM崩溃。那:插值相当于String.to_atom("text_#{locale}")
。
对于编辑过的问题:函数的API看起来很奇怪。有可能采用更好的方法来实现您想要实现的目标。但如果你真的需要这样做,这是我现在能想到的最简单的方法:
def listAll(dataSchema, fields) do
dataSchema
|> select([m], %{m | text: field(m, ^text_field)})
|> order()
|> Repo.all()
|> Enum.map(fn record ->
Enum.reduce(fields, record, fn field, record ->
# You might want to replace the Regex with something faster like `:binary.match` + `:binary.part` since you only need to find a '_' and remove everything after that.
without_suffix = field |> Atom.to_string |> String.replace(~r/_.*/, "") |> String.to_existing_atom
Map.put(record, without_suffix, Map.get(record, field))
end)
end)
end