martasd

martasd

In my Ecto schema, I have a User who has_many Items. An item has a boolean field active:

User module:

  schema "users" do
    field :name, :string
    has_many :items, Item
  end

Item module:

  schema "items" do
    field(:active, :boolean)
    belongs_to(:user, User)
  end

How can I ensure that a User has at most one item active? Thus, if a user already has an active item, the insertion of another active item should result in an error. The insertion of a new item with active: false should succeed, though.

It seems that exclusion_constraint could be used for that, but I haven’t found any docs showing how to use for anything other than overlapping time intervals.

Showing Posts 1 to 8

LostKobrakai

LostKobrakai

A partial unique constraint can do that as well.

create unique_index(:table, [:user_id], where: "active = TRUE")
wmnnd

wmnnd

The easiest way to solve this is probably to store nil/NULL instead of false. Then you can use a regular unique index because it only applies to non-NULL values.

christhekeele

christhekeele

Adding onto this, you can coerce false to nil in your Item changesets to prevent accidentally writing a false.

I think this approach may work even cleaner.


Either way, after doing one of them you can add :active_item like so to your User schema for easy access:

  schema "users" do
    field :name, :string
    has_many :items, Item
    has_one :active_item, Item, where: [active: true]

    timestamps()
  end
martasd

martasd OP

Thank you! I didn’t know that creating a unique index actually creates a constraint.

martasd

martasd OP

Nice, didn’t know that you could use the where option like this. :+1:

christhekeele

christhekeele

Yep! IIRC it will even populate the active field for you using certain association helpers, tho I forget exactly which.

al2o3cr

al2o3cr

When making a partial index like this, consider if you’ll ever want to query for “every row for a user_id” in production. If so, make sure there’s also an index that covers inactive records.

One less-visible way you might end up doing those kind of queries is if you cascade-delete records when a User is deleted.

The tricky part is that the system will work fine without that index… for a while. If the all-rows-for-a-user queries aren’t common, possibly a LONG while. And then suddenly :table has 100 million rows in it and your DBA is very very unhappy and your operations team is figuring out how many dozens of hours of degraded performance it will take to build the needed index… :scream_cat:

sodapopcan

sodapopcan

I’d never thought of that before, thanks!

— All posts loaded —

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
Blokh
Hey guys, I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly Do you guys have any suggestions what is the best prac...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
Onor.io
I have what I’ve heard referred to as a “lookup table” in my database. This is a way of assigning codes to common values. One common lo...
New
jaybe78
Hello, I’m developing a online persistent chat system (what’s app) like using elixir/dynamodb/aws for a mobile app(flutter). The diffic...
New
Trolleger
What approach to take when sending live updates to “random” users Hi! I have a question, I have a little chat app, and when I create a DM...
New
widianto
I think I’ve found a small improvement I could contribute to <%= web_namespace %>.CoreComponents (installer/templates/phx_web/compo...
New

Other Trending Topics Top

garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
wintermeyer
There are three potential reasons for members of this forum to have a look at https://vutuv.de You are tired or annoyed of LinkedIn. Yo...
New
webofbits
Aludel - LLM Evaluation Workbench Aludel is an embeddable Phoenix LiveView dashboard for evaluating and comparing LLM prompts across mult...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews