JSON to ecto

I have json I get from a web server:

[{“orodrNum”:“1742997”,“orinv”:“1767409”,“orseq”:" “,“orbdat”:“2020-01-02”,“orbamt”:“1033.01”,“ortamt”:“1033.01”,“orblst”:“Y”,“orarst”:“1”,“orfsc”:“146.41”,“ortfsc”:“146.41”,“orbint”:“SMO”},{“orodrNum”:“1745954”,“orinv”:“1767454”,“orseq”:” “,“orbdat”:“2020-01-02”,“orbamt”:“2357.45”,“ortamt”:“2357.45”,“orblst”:“Y”,“orarst”:“1”,“orfsc”:“526.41”,“ortfsc”:“526.41”,“orbint”:“BRJ”},{“orodrNum”:“1747279”,“orinv”:“1767450”,“orseq”:” “,“orbdat”:“2020-01-02”,“orbamt”:“4419.60”,“ortamt”:“4419.60”,“orblst”:“Y”,“orarst”:“1”,“orfsc”:“658.80”,“ortfsc”:“658.80”,“orbint”:“BRJ”},{“orodrNum”:“1747479”,“orinv”:“1767606”,“orseq”:” “,“orbdat”:“2020-01-02”,“orbamt”:“2872.05”,“ortamt”:“2872.05”,“orblst”:“Y”,“orarst”:“1”,“orfsc”:“560.40”,“ortfsc”:“560.40”,“orbint”:“EVS”},{“orodrNum”:“1747809”,“orinv”:“1767605”,“orseq”:” ",“orbdat”:“2020-01-02”,“orbamt”:“1228.78”,“ortamt”:“1228.78”,“orblst”:“Y”,“orarst”:“1”,“orfsc”:“98.22”,“ortfsc”:“98.22”,“orbint”:“EVS”}]

And I want to create a new Order for each json object using Ecto (postgres) with a changeset.

How do I iterate/enum/map through the data? I currently have Poison to decode/parse but I’m not married to it or anything really. I just want take each of these orders from the json that comes from the webserver and store it as a row in the postgres db.

1 Like

If you are using Poison you’ll need to decode the string first: https://hexdocs.pm/poison/Poison.html#decode!/1

Then you can use Enum.each to iterate over the result: https://hexdocs.pm/elixir/Enum.html#each/2

Inserting the data via Ecto will depend on your schema definition, but if you are following Phoenix conventions it might look something like Order.changeset(row) |> Repo.insert

All together:

Poison.decode!(json)
|> Enum.each(fn row -> Order.changeset(row) |> Repo.insert end)

That just ignore the result of the insert. Probably you will want to use transactions or some sort of temporary store to check for and handle error cases.

3 Likes

In addition, after decoding json (There is Jason as Poison alternative) You might use Repo.insert_all to insert all records with one request…

2 Likes

Thank you. When I compile this, it gives
warning: function Ecco.Documents.Ordbill.changeset/1 is undefined or private. Did you mean: * changeset/2

My function:

def create_ordbill(json) do
Poison.decode!(json)
|> Enum.each(fn row → Ordbill.changeset(row) |> Repo.insert end)
end

And then Ordbill.ex

defmodule Ecco.Documents.Ordbill do
use Ecto.Schema
import Ecto.Changeset

schema “ordbills” do
field :orodrNum, :string
field :orinv, :string
field :orseq, :string
field :orbdat, :date
field :orbamt, :float
field :ortamt, :float
field :orblst, :string
field :orarst, :string
field :orfsc, :float
field :ortfsc, :float
field :orbint, :string
timestamps()
end

def changeset(ordbill, attrs) do
ordbill
|> cast(attrs, [:orodr, :orinv, :orseq, :orbdat, :orbamt, :ortamt, :orblst, :orarst, :orfsc, :ortfsc, :orbint])
end
end

So do I need to rewrite the changeset function? Or pass in something else?

You need to pass a struct as first parameter of changeset…

1 Like

Of course! Long day thank you!