Owens
Unique Index/Constraint allow duplicates ONLY when ALL references are null
Hello all,
I’m creating a chat app that automatically creates chats between different groups of people as well as individuals. I want to make sure it doesn’t create any duplicates for the chats between these groups, but also allows for individual chats (private) where all the references are nil.
create unique_index(:chats,
[:parent_organization_id, :organization_id, :cohort_id, :team_id])
My understanding is that if any reference above is nil, postgres will allow duplicates.
To fix this, @LostKobrakai recommends here to create indexes with coalesce’d values like so:
execute( "create unique index INDEX_NAME on TABLE
(
coalesce(parent_organization_id, ''),
coalesce(organization_id, ''),
coalesce(cohort_id, ''),
coalesce(team_id, '')
);
")
But the problem is I need to ALLOW duplicates when all the references are nil (which they will be for individual chats between users).
In other words,
I need to PREVENT duplicates for these
parent_organization_id: 1, organization_id: nil, cohort_id: nil, team_id: nil
parent_organization_id: 1, organization_id: 1, cohort_id: nil, team_id: nil
parent_organization_id: 1, organization_id: 1, cohort_id: 1, team_id: nil
parent_organization_id: nil, organization_id: 1, cohort_id: nil, team_id: nil
parent_organization_id: nil, organization_id: 1, cohort_id: 1, team_id: nil
and ALLOW duplicates for these
parent_organization_id: nil, organization_id: nil, cohort_id: nil, team_id: nil
Appreciate any thoughts. Thank you.
Marked As Solved
Owens
It worked after changing
coalesce(parent_organization_id, '')
to
coalesce(parent_organization_id, -1)
Full code:
def change do
drop unique_index(:chats, [:parent_organization_id, :organization_id, :cohort_id, :team_id])
execute( "create unique index chats_parent_organization_id_organization_id_cohort_id_team_id_index on chats
(
coalesce(parent_organization_id, -1),
coalesce(organization_id, -1),
coalesce(cohort_id, -1),
coalesce(team_id, -1)
) where type != 'direct'
")
end
Also Liked
benwilson512
@Owens One certainly easy option here is an additional direct or individual column that you set to true, and then you can just WHERE individual == false on your unique index. This does mean you have to set that value, but OTOH it also makes it much more explicit, whereas the version that relies on N columns being nil feels very implicit.
benwilson512
xecute( "create unique index INDEX_NAME on TABLE
(
coalesce(parent_organization_id, ''),
coalesce(organization_id, ''),
coalesce(cohort_id, ''),
coalesce(team_id, '')
) where individual == false
")
This marks what is called a “partial index” where the index only applies to the rows where the condition is true.








