Elixir/Phoenix 将 JSON 保存到 Postgres 数据库

4
我已经谷歌搜索过很多关于如何做这个的方法。
我使用了phx.gen生成器来生成一些CRUD。 我想在我的数据库中创建仓库并存储Github活动。
我的迁移:
def change do
  create table(:coderepos) do
    add :name, :string
    add :description, :string
    add :repo_name, :string
    add :activity_data_raw, :jsonb
    timestamps()
  end
end

我的模型:

schema "coderepos" do
  field :activity_data_raw, :map, default: %{}
  field :name, :string
  field :description, :string
  field :repo_name, :string
  timestamps()
end

在创建我的新仓库时(通过生成的HTML),
#Ecto.Changeset<
  action: :insert,
  changes: %{
    description: "Blah",
    name: "Blah",
    repo_name: "blah"
  },
  errors: [activity_data_raw: {"is invalid", [type: :map, validation: :cast]}],
  data: #App.Integrations.CodeRepo<>,
  valid?: false
>

我通过在控制器中的create函数的:error响应中执行IO.inspect(changeset)来获取上面的更改集。

我的创建函数:

def create(conn, %{"code_repo" => code_repo_params}) do
  case Integrations.create_code_repo(code_repo_params) do
    {:ok, code_repo} ->
      conn
      |> put_flash(:info, "Code repo created successfully.")
      |> redirect(to: code_repo_path(conn, :show, code_repo))
    {:error, %Ecto.Changeset{} = changeset} ->
      render(conn, "new.html", changeset: changeset)
      IO.inspect(changeset)
  end
end

这是我在表单中提交的JSON代码片段(包括名称、说明和存储库名称): [{"week": 1532822400, "total": 6, "days": [0, 6, 0, 0, 0, 0, 0]}] 请注意,我在应用程序中做其他事情时,将其保存到我的数据库中没有任何问题。Postgres 10.4,Elixir 1.6.5 / OTP 20,Phoenix 1.3.3,Phoenix Ecto 3.2。如果您能提供任何帮助,将不胜感激!

你是将那个列表作为 activity_data_raw 传递吗?你已经定义它为一个映射,而不是列表。 - Dogbert
我查看了这里列出的原始类型:https://hexdocs.pm/ecto/Ecto.Schema.html#content,根据下面的部分,似乎使用映射来存储JSON是可行的 :| 我在我的mix文件中添加了Poison等内容,但我想我不知道该怎么做了。 - RuZ
1
你能发布完整的 JSON 值吗?如果你想存储一组映射,你需要将类型设置为 {:array, :map} - Dogbert
从Github返回的完整JSON看起来像这样:[{"week": 1501977600, "total": 0, "days": [0, 0, 0, 0, 0, 0, 0]}, {"week": 1502582400, "total": 0, "days": [0, 0, 0, 0, 0, 0, 0]}, {"week": 1503187200, "total": 0, "days": [0, 0, 0, 0, 0, 0, 0]}]由于字符长度限制,我无法粘贴全部内容,但它只是更多相同的内容。我尝试按照您的建议更新类型,但它仍然显示为无效。附言:感谢您迄今为止的时间!非常感谢。 - RuZ
根据这里的内容,它应该“只是工作”。 - RuZ
1个回答

1
感谢 Elixir Slack 中的 @trevoke,现在这个功能已经可以使用了。你需要传递一个映射(我想这是显而易见的,尽管我读到的其他地方让它听起来像是已经被处理好了)。上面评论中的 Dogbert 实质上也在说同样的事情。
在 create 函数中:
raw = Map.get(code_repo_params, "activity_data_raw")
code_repo_params = Map.put(code_repo_params, "activity_data_raw", %{"data" => raw})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接