Sequelize Model Relationship - mysql

I have 2 models here -
user.js
module.exports = (sequelize, DataType) => {
const User = sequelize.define('user', {
id: {
autoIncrement: true,
primaryKey: true,
type: DataType.INTEGER
},
username: {
type: DataType.STRING,
unique: true,
validate: {
len:
{ args: [4, 20], msg: "Username should be contain 4-20 characters." },
isAlphanumeric:
{ msg: "Only letters and numbers are allowed" }
}
},
email: {
type: DataType.STRING,
unique: true,
validate: {
isEmail:
{ msg: "Provide proper email" }
}
},
password: DataType.STRING,
emailverified: DataType.BOOLEAN
});
User.associate = function (models) {
// associations can be defined here
};
userprofile.js
module.exports = (sequelize, DataTypes) => {
var userprofile = sequelize.define('userprofile', {
nickName: DataTypes.STRING,
firstName: DataTypes.STRING,
middleName: DataTypes.STRING,
lastName: DataTypes.STRING,
gender: DataTypes.INTEGER,
age: DataTypes.INTEGER,
country: DataTypes.INTEGER,
steamUrl: DataTypes.STRING,
city: DataTypes.INTEGER,
status: DataTypes.STRING
}, {});
userprofile.associate = function (models) {
// associations can be defined here
};
return userprofile;
};
Can someone give an example on how to set 1: N relationship from user to userprofile i.e, 1 user can have N number of userprofiles and also by creating this relationship will a record be auto-generated under userprofiles table whenever a user is created?
Thank you

Did some research -
ref: https://github.com/sequelize/express-example/blob/master/models/user.js
module.exports = (sequelize, DataType) => {
const User = sequelize.define('user', {
id: {
autoIncrement: true,
primaryKey: true,
type: DataType.INTEGER
},
username: {
type: DataType.STRING,
unique: true,
validate: {
len:
{ args: [4, 20], msg: "Username should be contain 4-20 characters." },
isAlphanumeric:
{ msg: "Only letters and numbers are allowed" }
}
},
email: {
type: DataType.STRING,
unique: true,
validate: {
isEmail:
{ msg: "Provide proper email" }
}
},
password: DataType.STRING,
emailverified: DataType.BOOLEAN
});
User.associate = (models) => {
User.hasMany(models.userprofile, {
foreignKey: 'userid',
});
};
The above code creates a foreign key in userprofile table and auto-generation is not done.

Related

hasMany() associations can not be define in Squelize.js?

This is the teacher Table's Schema
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = require('../util/databaseConnection');
const Teacher = sequelize.define("teacher", {
teacherid: {
type: DataTypes.STRING,
allowNull: false,
primaryKey: true
},
surname: {
type: DataTypes.STRING,
allowNull: true
},
firstname: {
type: DataTypes.STRING,
allowNull: true
},
lastname: {
type: DataTypes.STRING,
allowNull: true
}
})
module.exports = Teacher;
This is the subject Model's Schema
const { Sequelize, DataTypes } = require("sequelize");
const sequelize = require('../util/databaseConnection');
const Subject = sequelize.define('subject', {
subjectid: {
type: DataTypes.INTEGER,
AutoIncrement: true,
primaryKey: true
},
subjectname: {
type: DataTypes.STRING
},
grade: {
type: DataTypes.STRING
},
subjectinfo: {
type: DataTypes.STRING
}
})
module.exports = Subject;
I need to define the association between teacher hasMany subject
Teacher.hasMany(Subject)
But following error
Naming collision between attribute 'subjects' and association
'subjects' on model teacher. To remedy this, change either foreignKey
or as in your association definition
You have to add Following keys
Teacher.hasMany(Subject, { foreignKey: 'teacher_id', targetKey: 'id' });
and in Subject model add following column
teacher_id: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'teacher',
key: 'id'
}
},

Sequelize - ORM - Associations not working

Using Sequelize with MySQL. I have three models. Consultant, FamilyMember and Appointments. Appointment refers to Consultant and FamilyMember.
I have defined the foreign keys in the Appointment model. When the DB is created - the foreign keys are visible - when I check through a MySQL client, on the appointment table. The table names are freeze - so there isn't any chance of pluralization of the table names.
Consultant Model:
module.exports = (sequelize, DataTypes) => {
const consultant = sequelize.define('consultant', {
ID: {
type: DataTypes.UUID,
primaryKey: true,
allowNull: false
},
FirstName: {
type: DataTypes.STRING,
allowNull: false
},
LastName: {
type: DataTypes.STRING,
allowNull: false
}
{
freezeTableName: true
}
);
return consultant;
};
Appointment Model:
module.exports = (sequelize, DataTypes) => {
const appointment = sequelize.define('appointment', {
// attributes
ID: {
type: DataTypes.UUID,
primaryKey: true,
allowNull: false
},
ConsultantID: {
type: DataTypes.UUID,
allowNull: false,
references: {
model: 'consultant',
key: 'ID'
}
},
FamilyMemberID: {
type: DataTypes.UUID,
allowNull: false,
references: {
model: 'familymember',
key: 'ID'
}
}
},
{
freezeTableName: true
}
);
appointment.associate = function (models) {
models.appointment.belongsTo(models.consultant, {
foreignKey: 'ConsultantID',
as: 'consultant',
});
models.appointment.belongsTo(models.familymember, {
foreignKey: 'FamilyMemberID',
as: 'familymember',
});
};
return appointment;
};
Family Member model:
module.exports = (sequelize, DataTypes) => {
const familymember = sequelize.define('familymember', {
// attributes
ID: {
primaryKey: true,
type: DataTypes.UUID,
allowNull: false
},
FamilyID: {
type: DataTypes.UUID,
allowNull: false
},
FirstName: {
type: DataTypes.STRING,
allowNull: false
},
LastName: {
type: DataTypes.STRING,
allowNull: false
}
},
{
freezeTableName: true
}
);
return familymember;
};
Then in the code I try to fetch appointment and get the related familymember and consultant like this
var appointments = await Appointment.findAll({
where: {
AppointmentDateConfirmed: {
$gte: moment().subtract(0, 'days').toDate()
}
}, include:[Consultant, FamilyMember]
}
)
However I get an error
UnhandledPromiseRejectionWarning: SequelizeEagerLoadingError: consultant is not associated to appointment!
I suppose you should register your associations after models registration like I pointed in this answer

SequelizeEagerLoadingError: product is not associated to collection

I use sequelize ORM in Mysql. I have 3 Models: Product, Collection, CollectionProduct
relationship between Product and Collection are many to many and for handle this in sequelize i used belongsToMany association. every thing is Ok but when i run this code to get a collection with its products with include Eager this error occure:
SequelizeEagerLoadingError: product is not associated to collection!
Product Model:
module.exports = (sequelize, Sequelize) => {
const Product = sequelize.define('product', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
name_en: {
type: Sequelize.STRING(255),
},
description_en: {
type: Sequelize.STRING(1024),
},
price: {
type: Sequelize.FLOAT,
allowNull: false,
},
type: {
type: Sequelize.STRING(255),
},
height: {
type: Sequelize.INTEGER,
},
width: {
type: Sequelize.INTEGER,
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
updatedAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
}, {})
Product.associate = (models) => {
Product.belongsToMany(models.collection, { through: models.collectionProduct, as: 'collections', foreignKey: 'productId' })
}
return Product
}
Collection Model :
module.exports = (sequelize, Sequelize) => {
const Collection = sequelize.define(
'collection', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
allowNull: false,
autoIncrement: true,
},
name_en: {
type: Sequelize.STRING(255),
},
itemsCount: {
type: Sequelize.INTEGER,
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
updatedAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
}, {},
)
Collection.associate = (models) => {
Collection.belongsToMany(models.product, { through: models.collectionProduct, as: 'products', foreignKey: 'collectionId' })
}
return Collection
}
CollectionProduct Model:
module.exports = (sequelize, Sequelize) => {
const CollectionProduct = sequelize.define('collectionProduct', {
collectionId: {
type: Sequelize.INTEGER,
},
productId: {
type: Sequelize.INTEGER,
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
updatedAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
}, {})
CollectionProduct.associate = (models) => {}
return CollectionProduct
}
routes/collection.js
const express = require('express')
const router = express.Router()
const Collection = require('../../controllers/collectionController')
router.get('/:id', async (req, res) => {
const { id: collectionId } = req.params
const collection = await Collection.getOne(collectionId)
return collection
}
collectionController
const db = require('../models/index')
const Collection = db.collection
const Product = db.product
const getOne = async (collectionId) => {
const collection = await Collection.findByPk(collectionId, {
include: {
model: Product,
as: 'products',
attributes: ['id', 'name_en'],
},
})
return collection
}
I found my problem. in collectionController i used model: Product
and Product should be a sequelize model. but in my code this is a function that have been called in models/index. so i changed my calling and pass a sequelize model to getOne

How to properly resolve query MySql using sequelize and Graphql

I am learning GraphQL and trying to get data from MySql tables via sequelize in the resolve function on GraphQL. I have a Clients table associated with a Pets Table, where Pets belong to Client.
Here is my code:
const PetsType = new GraphQLObjectType({
name: "Pet",
fields: () => ({
id: { type: GraphQLString },
name: { type: GraphQLString },
breed: { type: GraphQLString },
type: { type: GraphQLString },
ClientId: { type: GraphQLString },
Comments: {
type: CommentsType,
resolve(parentValue, args) {
return db.Comments;
}
}
})
});
const ClientType = new GraphQLObjectType({
name: "Client",
fields: () => ({
id: { type: GraphQLString },
lastName: { type: GraphQLString },
firstName: { type: GraphQLString },
primaryPhoneNumber: { type: GraphQLString },
cellphone: { type: GraphQLString },
workPhone: { type: GraphQLString },
email: { type: GraphQLString },
Pets: {
type: PetsType,
resolve(parentValue, args) {
return db.Pet.findOne({
where: { ClientId: parentValue.id }
});
}
}
})
});
Using findOne works for clients with only one pet or only returns the first pet of a client who owns more than one. However, some clients have more than one pet, so findOne() doesn't really solve my problem.
I've tried:
return db.Pet.findAll({
where: { ClientId: parentValue.id }
});
But it returns the client with the fields on Pets null.
Here are my Sequelize models for both, Clients and Pets:
Clients:
module.exports = function(sequelize, DataTypes) {
var Client = sequelize.define(
"Client",
{
lastName: {
type: DataTypes.TEXT,
allowNull: false,
len: [1]
},
firstName: {
type: DataTypes.TEXT,
allowNull: false,
len: [1]
},
primaryPhoneNumber: {
type: DataTypes.TEXT,
allowNull: true,
len: [1]
},
cellphone: {
type: DataTypes.TEXT,
allowNull: true,
len: [1]
},
workPhone: {
type: DataTypes.TEXT,
allowNull: true,
len: [1]
},
email: {
type: DataTypes.TEXT,
allowNull: true,
len: [1]
}
},
{
timestamps: false
}
);
Client.associate = function(models) {
// Associating Clients with Pets
// When a Client is deleted, also delete any associated Pets
Client.belongsTo(models.User);
Client.hasMany(models.Pet, {
onDelete: "cascade"
});
};
return Client;
};
Pets:
module.exports = function(sequelize, DataTypes) {
var Pet = sequelize.define(
"Pet",
{
name: {
type: DataTypes.TEXT,
allowNull: false,
len: [1]
},
breed: {
type: DataTypes.TEXT,
allowNull: false,
len: [1]
},
type: {
type: DataTypes.TEXT,
allowNull: true
}
},
{
timestamps: false
}
);
Pet.associate = function(models) {
Pet.belongsTo(models.Client);
Pet.hasMany(models.Comment, {
onDelete: "cascade"
});
};
return Pet;
};
How can I retreive all Pets that belong to this client?
Thanks in advance.
As Daniel Rearden suggested, I changed it to: type: new GraphQLList(PetsType) to return a list of objects

SequelizeForeignKeyConstraintError

I'm having problems with associations using Sequelize. I'm trying to create a Task, and it should belong to a User and a Department.
Here is my Task file:
module.exports = function (sequelize, DataTypes) {
var Task = sequelize.define("Task", {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
task_name: {
type: DataTypes.STRING,
notNull: true
},
description: {
type: DataTypes.STRING,
notNull: true
},
completed: {
type: DataTypes.BOOLEAN
}
}, {
tableName: 'tasks',
timestamps: false,
});
Task.associate = function (models) {
Task.belongsTo(models.Department, {
onDelete: 'CASCADE',
allowNull: true
});
Task.belongsTo(models.User, {
onDelete: 'CASCADE',
allowNull: true
});
}
return Task;
};
My departments file:
module.exports = function (sequelize, DataTypes) {
var Department = sequelize.define("Department", {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
departmentName: DataTypes.STRING,
description: {
type: DataTypes.STRING,
notNull: true
}
}, {
tableName: 'departments',
timestamps: false,
});
Department.associate = function (models) {
Department.belongsTo(models.Project, {
allowNull: true
});
Department.hasMany(models.Task, {
allowNull: true
});
}
return Department;
};
And finally my User file:
const bcrypt = require('bcryptjs');
module.exports = function (sequelize, Sequelize) {
var User = sequelize.define('User', {
id: {
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
fullname: {
type: Sequelize.STRING,
notEmpty: true
},
username: {
type: Sequelize.TEXT
},
email: {
type: Sequelize.STRING,
validate: {
isEmail: true
}
},
password: {
type: Sequelize.STRING,
allowNull: false
},
last_login: {
type: Sequelize.STRING
}
}, {
tableName: 'users',
timestamps: false
});
User.associate = function (models) {
User.hasMany(models.Task, {});
}
User.prototype.validPassword = function (password) {
return bcrypt.compareSync(password, this.password);
};
User.hook("beforeCreate", (instance) => {
if (instance.password) {
instance.password = bcrypt.hashSync(instance.password, bcrypt.genSaltSync(10), null);
}
});
return User;
}
I have googled high and low for an answer to this and I cannot find anything! Help is much appreciated.