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:

|> 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.


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


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
|> Enum.each(fn row -> Ordbill.changeset(row) |> Repo.insert 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

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

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!