在Elixir中将ecto模式写入CSV文件?

时间:2018-09-22 15:06:00

标签: csv elixir phoenix-framework

嗨,我的药水里有这样的Person模式

[
  %Texting.Contact.Person{
    __meta__: #Ecto.Schema.Metadata<:loaded, "people">,
    email: nil,
    name: "John",
    phone_number: "13334445555",
    phonebook: #Ecto.Association.NotLoaded<association :phonebook is not loaded>,
    phonebook_id: 60,
    previous_phonebook_id: 60,
    subscribed: true,
    updated_at: ~N[2018-09-22 14:36:04.788163],
    user: #Ecto.Association.NotLoaded<association :user is not loaded>,
    user_id: 54
  },
  %Texting.Contact.Person{
    __meta__: #Ecto.Schema.Metadata<:loaded, "people">,
    email: nil,
    name: "Rhee",
    phone_number: "14443335555",
    phonebook: #Ecto.Association.NotLoaded<association :phonebook is not loaded>,
    phonebook_id: 60,
    previous_phonebook_id: 60,
    subscribed: true,
    updated_at: ~N[2018-09-22 14:36:13.671479],
    user: #Ecto.Association.NotLoaded<association :user is not loaded>,
    user_id: 54
  }
]

我想将其保存为csv文件格式。所以我做到了

def write!(people) do
    file = File.open("contacts.csv", [:write, :utf8])
    people
    |> Enum.map(&Map.from_struct(&1))
    |> Enum.map(&CSV.encode(&1, headers: [:name, :phone_number]))
    |> Enum.map(&IO.write(file, &1))
end

但是我遇到了这样的错误

** (Protocol.UndefinedError) protocol String.Chars not implemented for #Function<62.51129937/2 in Stream.transform/3>. This protocol is implemented for: Atom, BitString, Date, DateTime, Decimal, Ecto.Date, Ecto.DateTime, Ecto.Time, Float, Floki.Selector, Floki.Selector.AttributeSelector, Floki.Selector.Combinator, Floki.Selector.Functional, Floki.Selector.PseudoClass, Integer, List, NaiveDateTime, Postgrex.Copy, Postgrex.Query, Postgrex.Stream, Time, URI, Version, Version.Requirement
    (elixir) /home/ubuntu/bob/tmp/0a92cc555e2418d1b56e3b10e5321a85/elixir/lib/elixir/lib/string/chars.ex:3: String.Chars.impl_for!/1
    (elixir) /home/ubuntu/bob/tmp/0a92cc555e2418d1b56e3b10e5321a85/elixir/lib/elixir/lib/string/chars.ex:22: String.Chars.to_string/1
    (elixir) lib/io.ex:553: IO.write/2
    (elixir) lib/enum.ex:1314: Enum."-map/2-lists^map/1-0-"/2

我要做的是仅将名称和phone_number字段保存为csv文件格式。 我该怎么办?

1 个答案:

答案 0 :(得分:3)

根据the documentationCSV.encode/2会获取字符串列表,并且没有您尝试使用的选项。

这就是我要做的:

def write!(people) do
  people
  |> Stream.map(&[&1.name, &1.phone_number])
  |> CSV.encode()
  |> Enum.into(File.stream!("contacts.csv"))
end

Enum.map创建一个字符串列表,然后将其编码并流式传输到contacts.csv

要在顶部添加标题行,可以使用Stream.concat/2在标题行之前添加

def write!(people) do
  [["name", "phone_number"]]
  |> Stream.concat(people |> Stream.map(&[&1.name, &1.phone_number]))
  |> CSV.encode()
  |> Enum.into(File.stream!("contacts.csv"))
end