hasMany foreignKey not working in Sequelize - postgresql

I have some models - kanban_cards, kanban_checklists, kanban_checkitems.
kanban_cards model:
export default (sequelize, DataTypes) => {
return sequelize.define('kanban_card', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
allowNull: false
},
label: {
type: DataTypes.STRING,
allowNull: true,
},
listId: {
type: DataTypes.UUID,
allowNull: false
},
...
})
}
kanban_checklist:
export default (sequelize, DataTypes) => {
return sequelize.define('kanban_checklist', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
allowNull: false
},
cardId: {
type: DataTypes.UUID,
allowNull: false,
}
})
}
And the association is:
const models = {
KanbanCards: KanbanCards(sequelize, Sequelize.DataTypes),
KanbanChecklists: KanbanChecklists(sequelize, Sequelize.DataTypes),
...
}
...
models.KanbanCards.hasMany(models.KanbanChecklists, { as: 'checklists', foreignKey: 'cardId' })
models.KanbanChecklists.belongsTo(models.KanbanCards)
It works fine if I use findAll, but if I try to create, it doesn't work.
It says.
column "kanbanCardId" of relation "kanban_checklists" does not exist
I am going to use cardId rather than kanbanCardId.
I tried to set references to cardId, but it didn't work either.

If you indicated an explicit foreign key column in hasMany you should do the same for the other part - belongsTo:
models.KanbanChecklists.belongsTo(models.KanbanCards, { foreignKey: 'cardId' })
Otherwise Sequelize generate a foreign key name itself like in your case kanbanCard+id:
The name of the foreign key in the join table (representing the target model) or an object representing the type definition for the other column (see Sequelize.define for syntax). When using an object, you can add a name property to set the name of the column. Defaults to the name of target + primary key of target

Related

SequelizeDatabaseError: the operator does not exist : integer = boolean when using special methods on model instance

I have two models in Many-to-Many association : Agency and Customer.
UPDATE : (here are the models and association definition)
Agency :
const agency = (sequelize, DataTypes) => {
const Agency = sequelize.define('agency', {
name: {
type: DataTypes.STRING,
allowNull: false,
validate: {
notEmpty: true,
}
},
});
Agency.associate = models => {
Agency.hasMany(models.User, { onDelete: 'CASCADE' });
Agency.belongsToMany(models.Customer, { onDelete: 'SET NULL', through: 'CustomerAgencies'});
};
return Agency;
};
export default agency;
Customer :
const customer = (sequelize, DataTypes) => {
const Customer = sequelize.define('customer', {
email: {
type: DataTypes.STRING,
unique: true,
allowNull: false,
validate: {
notEmpty: true,
isEmail: true,
},
},
firstname: {
type: DataTypes.STRING,
allowNull: true,
validate: {
notEmpty: true,
}
},
lastname: {
type: DataTypes.STRING,
allowNull: true,
validate: {
notEmpty: true,
}
},
phone: {
type: DataTypes.INTEGER,
},
language: {
type: DataTypes.STRING,
},
});
Customer.associate = models => {
Customer.belongsToMany(models.Agency, { onDelete: 'SET NULL', through: 'CustomerAgencies'});
};
return Customer;
};
export default customer;
When i create some entries, there is no problem :
const agency = await models.Agency.findOrCreate({
where: { name: 'SunTour'},
defaults: {
name: 'SunTour'
}
});
const customer = await models.Customer.findOrCreate({
where: { email: 'paulo#example.com' },
defaults: {
email: 'paulo#example.com',
firstname: 'Paulo',
lastname: 'Dena',
phone: '0202020202',
},
});
But i'm trying to use the special methods of Sequelize that are available when two models are in relation.
Juste under the previous code example i wrote this to check is there is already an assocation between the two instances :
debug(await customer[0].hasAgency(agency));
The node server return me the error below for this line :
UnhandledPromiseRejectionWarning: SequelizeDatabaseError: the operator does not exist : integer = boolean
In the console the query executed is this one :
SELECT "agency"."id" FROM "agencies" AS "agency" INNER JOIN "CustomerAgencies" AS "CustomerAgencies" ON "agency"."id" = "CustomerAgencies"."agencyId" AND "CustomerAgencies"."customerId" = 1 WHERE ((("agency"."id" = 1 OR "agency"."id" = false)));
You can see that Sequelize query is using "agency.id = false" in his condition, i guess that's the problem.
Note : i'm using a PostGreSQL Database.
I guess the problem come from the PostGreSQL Database, but what can i do ?
Thanks in advance.

SailsJs/Postgresql - How to create a one way association or one-to-many relation via an unique field

I have two models:
PdfAnnotation.js:
module.exports = {
tableName: "pdf_annotations",
primaryKey: "pk_id",
attributes: {
pk_id: {
type: "number",
autoIncrement: true
},
annotation_id: {
type: "string",
unique: true,
required: true,
},
comments: {
collection: "pdfcomments",
via: "fk_annotation_id"
}
}
};
PdfComments.js:
module.exports = {
tableName: "pdf_comments",
primaryKey: "pk_id",
attributes: {
pk_id: {
type: "number",
autoIncrement: true,
},
fk_annotation_id: {
model: "pdfannotations",
},
comment_content: {
type: "string",
},
}
};
When I run these codes:
PdfAnnotations.create({
annotation_id: "test3",
});
PdfComments.create({
fk_annotation_id: 'test3',
comment_content: 'test',
});
I got this error:
I have followed the documentation: https://sailsjs.com/documentation/concepts/models-and-orm/associations/one-to-many.
The difference between my implementation and the docs is: the constraint I used for PdfComments to PdfAnnotations via an unique field annotation_id(string) not the primary key pk_id(number), so that I got the error.
For some reasons I don't want to use annotation_id as a primary key (such as its type is string)
I'm not familiar with Sails and its ORM, hope to see your help.
Try something like this:
const pdfannotation = await PdfAnnotations.create({
annotation_id: 'test3',
}).fetch();
const pdfcomment = await PdfComments.create({
fk_annotation_id: pdfannotation.id,
comment_content: 'test',
});

Sequelize delete instance with n:m and 1:m associations and update Model

I have 2 models in my postgresql db and using sequelize and node:
Users
Transactions
and are associated like this:
UserModel.hasMany(TransactionModel, { as: 'sentTransactions', foreignKey: 'senderId' });
UserModel.hasMany(TransactionModel, { as: 'receivedTransactions', foreignKey: 'receiverId' });
UserModel.belongsToMany(TransactionModel, { as: 'transactionLikes', through: 'UserLike', foreignKey: 'userId' });
TransactionModel.belongsTo(UserModel, { as: 'receiver' });
TransactionModel.belongsTo(UserModel, { as: 'sender' });
TransactionModel.belongsToMany(UserModel, { as: 'likers', through: 'UserLike', foreignKey: 'transactionId' });
Which means a user has many received and sent transactions and each user can "like" many transactions.
How can I delete a transaction and remove all associations (receiver, sender, liker)? I don't want to delete the users too.
I would also like to update the User Model which is defined like this, in order to add an "email" property:
const UserModel = db.define('user', {
id: { type: Sequelize.STRING, unique: true, primaryKey: true },
firstName: { type: Sequelize.STRING },
lastName: { type: Sequelize.STRING },
username: {
type: Sequelize.STRING,
unique: {
args: true,
msg: USERNAME_IS_TAKEN,
},
}
How can I update the model? What will happen to the existing instances?
Thank you in advance for your help!
According to this tutorial your M:N relation should work as you expect it out of the box:
For n:m, the default for both is CASCADE. This means, that if you delete or update a row from one side of an n:m association, all the rows in the join table referencing that row will also be deleted or updated.
Further more, to enforce the CASCADE behavior you may also pass onDelete option to the association calls. Something like this should do the trick:
TransactionModel.belongsToMany(UserModel, { as: 'likers', through: 'UserLike', foreignKey: 'transactionId', onDelete: 'CASCADE' });
Adding an email property to the User Model should be as easy as that:
const UserModel = db.define('user', {
id: {
type: Sequelize.STRING,
unique: true,
primaryKey: true
},
firstName: { type: Sequelize.STRING },
lastName: { type: Sequelize.STRING },
username: {
type: Sequelize.STRING,
unique: {
args: true,
msg: USERNAME_IS_TAKEN,
}
},
email: { type: Sequelize.STRING }
});

How to set up PostgreSQL database with associations between tables (foreign keys) with Sequelize

I'm using PostgreSQL, Sequelize, and Sequelize-cli.
Using sequelize-cli and some manipulation in an IDE I set up the following model and migration file (simplified for the example, I didn't include the "Users" migration file):
Model File
// models/annotation.js
module.exports = function (sequelize, DataTypes) {
var Annotation = sequelize.define('Annotation', {
userId: {
type: DataTypes.INTEGER,
references: {model: "User", key: 'id'},
},
url: DataTypes.STRING,
source: DataTypes.STRING,
body: DataTypes.TEXT,
exact: DataTypes.TEXT,
}, {
classMethods: {
associate: function (models) {
// associations can be defined here
Annotation.belongsTo(models.User, {foreignKey: "userId"});
},
},
});
return Annotation;
};
Corresponding migration file
// migrations/20161121050521-create-annotation.js
const User = require("../models/user");
module.exports = {
up: function(queryInterface, Sequelize) {
return queryInterface.createTable('Annotations', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
userId: {
type: Sequelize.INTEGER,
references: {model: User, key: 'id'},
allowNull: false
},
...
Referenced Model
// models/user.js
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('User', {
title: DataTypes.STRING,
name: DataTypes.STRING,
email: DataTypes.STRING,
}, {
classMethods: {
associate: function(models) {
// associations can be defined here
User.hasMany(models.Annotation, {foreignKey: "userId"});
}
}
});
return User;
};
I'm running the follow cli commands:
"dropdb -U postgres annotate && curl -XDELETE 'http://localhost:9200/_all'"
"createdb -U postgres annotate"
"node_modules/.bin/sequelize db:migrate"
When I migrate I get the following error:
SequelizeDatabaseError: relation "User" does not exist
From the documentation I was under the impression that Annotation.belongsTo(models.User would have been enough to establish the association, but when I did that my db tables didn't have any foreign key fields.
How can I establish tables with associations to one another?

Sails js and Sequelize, no associations added to database

This is how my models are structured in sails:
myapp
--api
----controllers
----models
-----User.js
------Role.js
User.js
module.exports = {
attributes:{
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
username: {
type: Sequelize.STRING,
},
password: {
type: Sequelize.STRING,
}
},
associations: function() {
User.hasOne(Role, {foreignKey: 'id', as: 'role' });
}
};
Role.js
module.exports = {
attributes:{
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING,
}
}
};
After sails lift, in the postgresql I have users table with id, username, password, createdat and updatedat + roles table with id, name, createdat and updatedat. No foreignKey for Roles in Users table.
How I can fix this?
I'm using sails-hook-sequelize and sails-hook-sequelize-blueprints, can this occur because of them?
Thanks!
Edit:
The correct way was:
module.exports = {
attributes:{
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
username: {
type: Sequelize.STRING,
},
password: {
type: Sequelize.STRING,
}
},
associations: function() {
User.hasOne(Role, {
as : 'role',
foreignKey: {
name: 'roleId',
allowNull: false
}
});
}
};
The createdAt and updatedAt columns are added by default unless you set the timestamps option to false. See the docs.
To add foreign key constraints, you need to define associations for the Roles model.