ericteubert

ericteubert

Unique Index with multiple columns

I have a unqiue index over three columns where one is computed ([:file_id, :request_id, "(accessed_at::date)"]) and I can’t figure out how to use :conflict_target on insert correctly.

The Ecto docs made me understand that a unique_index creates a constraint so I could use conflict_target: {:constraint, :downloads_daily_unique_request_index} but that doesn’t seem to be the case.

Here’s my abbreviated setup:

# Migration
defmodule DemoApp.Repo.Migrations.CreateDownloads do
  use Ecto.Migration

  def change do
    create table(:downloads) do
      add :request_id, :string
      add :accessed_at, :utc_datetime
      add :file_id, references(:audio_files, on_delete: :nothing)

      timestamps()
    end

    create unique_index(
             :downloads,
             [:file_id, :request_id, "(accessed_at::date)"],
             name: :downloads_daily_unique_request_index
           )
  end
end
# Schema
defmodule DemoApp.Tracking.Download do
  use Ecto.Schema

  # ...

  schema "downloads" do
    field :request_id, :string
    field :accessed_at, :utc_datetime

    belongs_to :file, AudioFile

    timestamps()
  end

  @doc false
  def changeset(download, attrs) do
    download
    |> cast(attrs, [
      :request_id,
      :accessed_at
    ])
    |> validate_required([
      :request_id,
      :accessed_at
    ])
    |> unique_constraint(
      :request_id,
      name: :downloads_daily_unique_request_index
    )
  end
end

There doesn’t seem to be a constraint setup in the database:

Download.changeset(%Download{}, %{request_id: "fooxyz", accessed_at: DateTime.utc_now()})
|> Ecto.Changeset.put_assoc(:file, file)
|> Repo.insert(
  on_conflict: :nothing,
  conflict_target: {:constraint, :downloads_daily_unique_request_index}
)

** (Postgrex.Error) ERROR 42704 (undefined_object) constraint “downloads_daily_unique_request_index” for table “downloads” does not exist
query: INSERT INTO “downloads” (“accessed_at”,“file_id”,“request_id”,“inserted_at”,“updated_at”) VALUES ($1,$2,$3,$4,$5) ON CONFLICT ON CONSTRAINT “downloads_daily_unique_request_index” DO NOTHING RETURNING “id”

Listing the columns does not work because one of them is calculated:

Download.changeset(%Download{}, %{request_id: "fooxyz", accessed_at: DateTime.utc_now()})
|> Ecto.Changeset.put_assoc(:file, file)
|> Repo.insert(
  on_conflict: :nothing,
  conflict_target: [:file_id, :request_id, "accessed_at::date"]
)

** (Postgrex.Error) ERROR 42703 (undefined_column) column “accessed_at::date” does not exist

What am I missing?

Thanks!

Marked As Solved

al2o3cr

al2o3cr

Dunno if it works outside of Ecto.Query.from, but you might try adding import Ecto.Query to make fragment visible.

FWIW, the Postgres docs mention that the conflict target can be omitted for ON CONFLICT ... DO NOTHING cases.

Also Liked

ericteubert

ericteubert

:man_facepalming: Of course! All I care about is that no duplicates are inserted and that’s ensured by the index itself. Thanks!

Last Post!

ericteubert

ericteubert

:man_facepalming: Of course! All I care about is that no duplicates are inserted and that’s ensured by the index itself. Thanks!

Where Next?

Popular in Questions Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
Lily
In templates/appointment/index.html.eex: <%= for appointment <- @appointments do %> <tr> <td><%= appoi...
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
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

Other popular topics Top

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
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New

We're in Beta

About us Mission Statement