Sequelize Duplicate Key Constraint Violation - postgresql

I am trying to add a many to many relationship through an explicitly created junction table using Sequelize and Postgresql.
The tables on either side of the relationship are associated like this:
Shop.belongsToMany(models.user, {through: 'visits' })
User.belongsToMany(models.shop, {through: 'visits' })
And the visits junction table primary key is defined like this:
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true // Automatically gets converted to SERIAL for postgres
}
When I try and insert into visits I get the following error:
ERROR: duplicate key value violates unique constraint "visits_shopId_userId_key"
DETAIL: Key ("shopId", "userId")=(1, 12) already exists.
After doing a pg_dump, I have tried to remove the composite key constraint by adding constraint: false to the models, but I still get the error.
(I have dropped the tables and resynced several times during the debugging process)

After digging around the Sequelize issues, it turns out that removing the constraint on the N:M composite key is an easy fix.
The through key can take an object with the unique: false property:
Shop.belongsToMany(models.user, {
through: {
model: 'visits',
unique: false
},
constraints: false
});

Related

No unique constraint for composite foreign key, PostgreSQL

I am trying to relate an assosciative table with another table.
...
knex.schema.createTable("test", (table) => {
table.integer("subject_id").unsigned().references("id").inTable("subject").notNullable();
table.integer("duration_id").unsigned().references("id").inTable("duration").notNullable();
table.unique(["subject_id", "duration_id"]);
}),
knex.schema.createTable("exam", (table) => {
table.increments().notNullable();
table.integer("subject_id").unsigned();
table.integer("duration_id").unsigned();
...
...
table.foreign(["subject_id", "duration_id"]).references(["subject_id", "duration_id"]).inTable("test");
}),
...
throws the following error:
migration failed with error: alter table "exam" add constraint "exam_subject_id_duration_id_foreign" foreign key ("subject_id", "duration_id") references "test" ("subject_id", "duration_id")
- there is no unique constraint matching given keys for referenced table "test"
Having unique or primary key constraint for the two columns results in the same error. Is this a knex related error?
Moving the foreign key constraint after the unique constraint fixed the problem. Though I don't know the exact reason.
...
knex.schema.createTable("test", (table) => {
table.integer("subject_id").unsigned().notNullable();
table.integer("duration_id").unsigned().notNullable();
table.unique(["subject_id", "duration_id"]);
table.foreign("subject_id").references("id").inTable("subject");
table.foreign("duration_id").references("id").inTable("duration");
}),
knex.schema.createTable("exam", (table) => {
table.increments().notNullable();
table.integer("subject_id").unsigned();
table.integer("duration_id").unsigned();
...
...
table.foreign(["subject_id", "duration_id"]).references(["subject_id", "duration_id"]).inTable("test");
}),
...

Sequelize ON DELETE CASCADE

I have two tables, house, renter.
A house has many renters, a renter only has one house. (house <->> renter).
In Renter:
Renter.associate = function (models) {
models.renter.belongsTo(models.house, { foreignKey: { name: 'house_id', allowNull: false } } );
};
Or:
Renter.associate = function (models) {
models.renter.belongsTo(models.house, { foreignKey: { name: 'house_id', allowNull: false, onDelete:'CASCADE' } } );
};
Both ways fail as explained below.
In House:
House.associate = function (models) {
models.house.hasMany(models.renter, { foreignKey: 'house_id'});
}
I also tried by omitting the hasMany association and only having the belongsTo part on renter...
when I delete a hosue:
await house1.destroy();
I get the following error:
SequelizeForeignKeyConstraintError: update or delete on table "house" violates foreign key constraint "renter_house_id_fkey" on table "renter"
When I look at the db logs, during the renter table creation it has this:
"house_id" INTEGER NOT NULL REFERENCES "house" ("id") ON DELETE NO ACTION ON UPDATE CASCADE
I need the DB to delete all renters when I delete a house via DB constraint ON DELETE CASCADE. How can I fix this? As far as the table def goes, I can see the ON DELETE NO ACTION being a problem, and I am not sure how to get sequelize to put CASCADE not NO ACTION.

Sequelize upsert throws unique violation for schema with nullable unique column

I'm facing an unique constraint violation issue when doing an upsert, because the UPDATE query built by sequelize ignores the partial index constraint defined by the model (unless it doesn't matter). I'm new to node+sequelize so I might be missing something obvious, but I went through all the potential places for finding the appropriate answers, inclusive of the sequelize code, but I'm not able to find the answer I'm looking for. Really appreciate your help!
My current versions:
"pg": "7.9.0",
"sequelize": "5.21.3"
I have a model that consists of a primary key: id and two other unique indexes of which one of them is a nullable field.
module.exports.Entities = sequelize.define('entities', {
id: {type: Sequelize.UUID, defaultValue: Sequelize.UUIDV4, allowNull: false, primaryKey: true},
cId: {type: Sequelize.STRING, allowNull: false},
pId: {type: Sequelize.UUID, allowNull: false},
eKey: {type: Sequelize.INTEGER, allowNull: true}
}, {
indexes: [
{
name: 'unique_c_id_p_id',
fields: ['c_id', 'p_id'],
unique: true
},
{
name: 'unique_e_key',
fields: ['e_key'],
unique: true,
where: {
eKey: {
[Op.not]: null
}
}
}
]
})
and the table itself looks like below:
CREATE TABLE public.entities (
id UUID DEFAULT uuid_generate_v4 (),
c_id UUID NOT NULL,
p_id UUID NOT NULL,
e_key INTEGER DEFAULT NULL,
CONSTRAINT ENTITY_SERVICE_PKEY PRIMARY KEY (id),
CONSTRAINT unique_c_id_p_id UNIQUE (c_id, p_id)
);
CREATE UNIQUE INDEX unique_e_key ON public.entities (e_key) WHERE e_key IS NOT NULL;
The upsert method call looks like:
module.exports.upsert = async (Model, values) => Model.upsert(values, {returning: true})
I pass the above Entities model, and the below value as arguments to this function.
{
"id"="3169d4e2-8e2d-451e-8be0-40c0b28e2aa9",
"c_id"="00000000-0000-0000-0000-000000000000",
"p_id"="78bce392-4a15-4a8a-986b-c9398787345f",
"e_key"= null
}
Issue: SequelizeUniqueConstraintError
Sequelize tries to do an insert followed by an update query when we attempt to update an existing record using the upsert method.
The insert query shows a conflict, since the record exists already, and sequelize upsert call proceeds on to invoke the update query.
However, the query that it builds to UPDATE looks something like below:
"SQL statement UPDATE entities SET id='3169d4e2-8e2d-451e-8be0-40c0b28e2aa9',c_id='00000000-0000-0000-0000-000000000000',p_id='78bce392-4a15-4a8a-986b-c9398787345f',e_key=NULL
WHERE (id = '3169d4e2-8e2d-451e-8be0-40c0b28e2aa9'
OR e_key IS NULL
OR (c_id = '00000000-0000-0000-0000-000000000000' AND p_id = '78bce392-4a15-4a8a-986b-c9398787345f'))
RETURNING id\nPL/pgSQL function pg_temp_5.sequelize_upsert() line 1 at SQL statement"
Now, I do understand the reason why it's throwing the unique constraint violation, since in the above query's WHERE clause sequelize calls OR e_key IS NULL since e_key = null and that could potentially return more than 1 record, and the SET is trying to update the same value for all those records that were returned thereby violating the primaryKey constraints, unique constraints etc.
What I would like to understand is that:
Why does sequelize not exclude the e_key unique constraint based on the partial index defined given that it picks the WHERE clause attributes based on the constraints defined in the Model & it's indexes?
Is there anything that I could do to get past this issue?
Or, am I missing something obvious that I could fix and try?
Really appreciate you taking your time to read and respond. Thanks!

Structuring a hasura-graphql insert mutation query for an object with a one-to-many foreign key relationship

I'm having trouble building a hasura graphql query that inserts a row into a table that has multiple foreign key relationships.
I have three tables, "Users", "Groups", and "UserGroups". The "UserGroups" table has foreign key relationships on columns groupId, and userId. I used Hasura's UI to track the relationships that it had suggested based on the two foreign keys.
I can create new UserGroups by connecting to the database directly but when I try to create a new UserGroup through a graphql query I get a foreign key violation response.
{
"errors": [
{
"extensions": {
"path": "$.selectionSet.insert_user_group.args.objects",
"code": "constraint-violation"
},
"message": "Foreign key violation. insert or update on table \"user_group\" violates foreign key constraint \"user_group_userId_fkey\""
}
]
}
Here is the mutation I'm trying to use:
mutation insert_user_group {
insert_user_group(objects: [{
userId: 1,
groupId: 1,
}]) {
affected_rows
}
}
I was only able to find documentation regarding querying tables with one-to-many relationships but nothing showing how to construct an insert mutation.
Turns out it was failing because I wasn't using strings in the query for the id values. They are BigInt columns but the queries required strings for the insert to work correctly.
Thank you #praveenweb for your comment.

dead-lock scenario in grails when trying to do ORM

I am writing a simple grails (2.3.1) sample application which uses postgresql(9.1)
I have two domain classes 'Nose' and 'Face'.
//Nose class
package human
class Nose {
static belongsTo=[face:Face]
static constraints = {
face nullable: true
}
}
//Face class
package human
class Face {
static hasOne = [nose:Nose];
static constraints = {
nose nullable: true
}
}
My database is empty and I am using static scaffold.
Now, grails does not allow me to insert into either, because one has foreign key constraint with other.
Also, when i try to insert directly in the postgresql database, i get the same foreign key constraint error:
human=# insert into nose (id, version, face_id) values (1, 0, 1);
ERROR: insert or update on table "nose" violates foreign key constraint "fk33afd3c47bf8db"
DETAIL: Key (face_id)=(1) is not present in table "face".
OR
human=# insert into face (id, version, nose_id) values (1, 0, 1);
ERROR: insert or update on table "face" violates foreign key constraint "fk2fd65d8476fd1b"
DETAIL: Key (nose_id)=(1) is not present in table "nose".
human=#
How to resolve this dead-lock condition ?