dstpierre

dstpierre

Error with Enum.sort_by/3 (ArgumentError) you attempted to apply :field_name on)

Hi everyone,

I’m prototyping some queries that I would need at work should we decide to go with Elixir and I wanted to see how Elixir, Ecto, Plug, and Cowboy would feel to me in real world context.

I’m getting this error when doing a Enum.sort_by/3 and I’m not understanding what I’m doing wrong. Here’s my Ecto schema (abbreviated):

@primary_key {:id, :integer, source: :RefID}
  schema "Supplier" do
    field :company_id, :integer, source: :CompanyID
    field :supplier_id, :integer, source: :SupplierID
    # ...
    field :last_modified, :naive_datetime, source: :LastModified

I’m auto-generating all Schema from a C# Linq-To-SQL DBML (but that’s a story for a later post). I’d like to migrate to Elixir from outdated 15-20 years old C# legacy business web application.

This is the function I created that I’m running from IEx:

defmodule Data.Test do
  import Ecto.Query

  alias DB.HiddenName.Supplier
  alias DB.HiddenName.Repo

  def report(id) do
    sup = Supplier
      |> where([s], s.company_id == ^id)
      |> order_by([s], desc: s.last_modified)
      |> select([s], s)
      |> Repo.all()

    sup
    |> Enum.group_by(fn x -> x.supplier_id end)
    |> Enum.map(fn {_k, v} -> Enum.take(v, 4) end)
    |> Enum.sort_by(&(&1.last_modified), {:desc, NaiveDateTime})
  end
end

The error I’m getting:

** (ArgumentError) you attempted to apply :last_modified on [%DB.HiddenName.Supplier{supplier_id: 123, company_id: 6, last_modified: ~N[2019-06-18 15:32:00]], :last_modified, [])

When I comment out the last Enum.sort_by there’s no error. I tried replacing the &1.last_modified with the primary key id and just use :desc as the 3 argument, but I’m getting the same error with :id instead of the NaiveDateTime :last_modified.

In short, I just want to sort by that field, and I’ll be completely honest I’m not very sure what &(&1.last_modified) does exactly (I’m in my day 2 with Elixir),

Probably basics question but I’m not phrasing that properly to get any answer myself.

Thanks for your time and help.

Most Liked

hauleth

hauleth

Not an answer, but why not do all of that in the query (I assume PostgreSQL)?

from s in Supplier,
  where: s.company_id == ^id,
  order_by: [desc: :last_modified],
  group_by: s.supplier_id,
  select: fragment("array_agg(?)", s)

About your question, use Enum.flat_map/2 as your Enum.map/2 will return list of lists and in Enum.sort_by/3 you expect list of maps.

hauleth

hauleth

In SQL:2003 it could be written as:

SELECT *
FROM (
  SELECT
    s.*,
    dense_rank() over (PARTITION BY s.supplier_id ORDER BY s.last_modified DESC) rank
  FROM suppliers s
  ORDER BY s.last_modified DESC) q
WHERE rank < 5
ORDER BY q.last_modified DESC

http://sqlfiddle.com/#!17/bc507/12

Unfortunately Ecto AFAIK still do not allow to have select from subquery so we need to “hack around” by using JOIN:

SELECT s.*
FROM suppliers s
INNER JOIN (
  SELECT
    id,
    dense_rank() over (PARTITION BY supplier_id ORDER BY last_modified DESC) rank
  FROM suppliers) q
  ON q.id = s.id
WHERE q.rank < 5
ORDER BY s.last_modified DESC

http://sqlfiddle.com/#!17/f7eae/2

This one should be possible to express in Ecto syntax:

from s in Supplier,
  inner_join: q in subquery(from ns in Supplier,
                              select: %{
                                id: ns.id,
                                rank:
                                  row_number()
                                  |> over(partition_by: :supplier_id, order_by: {:desc, :last_modified})
                              }),
  on: s.id == q.id,
  where: q.rank < 5, # row_number is 1-based
  order_by: {:desc, :last_modified}

However this is all based on the assumption that the T-SQL supports window functions in SQL:2003 compatible way or that Ecto can translate above query to syntax used by MS SQL.

hauleth

hauleth

These are 100% identical. IIRC once one was implemented using another. There is no strong preference on one over another AFAIK but with time I personally prefer from macro as this do not force me to repeat the match over and over again. Use what you want TBH. Additional advantage of from for me is that it encourages people to write whole query in place as I found the “building” quite confusing (but that was pre-named joins, so nowadays it is probably nicer).

So answer is no, pipe and from are completely equivalent solutions and you can even mix them as you please.

Where Next?

Popular in Questions Top

Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
dokuzbir
Hello, I am trying to convert my lists to string without losing brackets.For start i have 3 map. They look like these buyer = %{ id: ...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
makeitrein
Hey all, just started picking up Elixir last week and am writing a scraper as a learning project. Baby step #1 is extracting the number ...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
chewm
Hi guys, nice to meet you to the whole forum, I’m new here, I’m trying to configure visual studio code for elixir, right now the intellis...
New
jc00ke
Expanding on this topic: https://forum.elixirforum.net/t/map-typespec-question/19217 Let’s say I have a map with required and optional k...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

Other popular topics Top

Tee
can someone please explain to me how Enum.reduce works with maps
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
Jim
As a follow up to my earlier question: I have the code compiling and running but not getting a successful login from the rest server. ...
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? https://hexdocs.pm/ecto/Ecto.Repo.h...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
AstonJ
by Lance Halvorsen Elixir and Phoenix are generating tremendous excitement as an unbeatable platform for building modern web application...
460 27162 124
New

We're in Beta

About us Mission Statement