Sequelize Update HasMany Relationships - mysql

I would like to update the rows of a hasMany relation, I have a table InRoutes that can have many InRouteDetails, so when I update InRoute I also need to update it details, there are three cases that can happen, delete an detail, update an detail and add an detail.
When I try to update using setInRouteDetails but for some reason he tries to get an InRouteDetail that is equal an object given me this error: Truncated incorrect DOUBLE value: '[object Object]'
This is my model:
export default (sequelize, DataType) => {
const InRoutes = sequelize.define('InRoutes', {
id: {
type: DataType.INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: {
type: DataType.STRING,
allowNull: false,
validate: {
notEmpty: true,
},
},
description: {
type: DataType.TEXT,
allowNull: true,
},
createdBy: {
type: DataType.STRING,
allowNull: true,
},
updatedBy: {
type: DataType.STRING,
allowNull: true,
},
}, {
classMethods: {
associate: (models) => {
InRoutes.hasMany(models.InRoutesDetails, {
foreignKey: 'InRouteId',
as: 'InRouteDetails',
onDelete: 'CASCADE',
});
InRoutes.belongsTo(models.Trunks, {
foreignKey: 'trunkId',
as: 'TrunkId',
onDelete: 'CASCADE',
});
},
},
});
return InRoutes;
};
This is where I try do update "InRoute" with his association "InRouteDetails":
async update(data, params, updatedBy) {
data.updatedBy = updatedBy.username;
try {
const inRoute = await this.InRoutes.findOne({ where: params });
const teste = [{
id: 2,
mask: '89',
remove: 4,
add: '3',
destinationType: 'callback',
destination: 2,
InRouteId: 2,
}];
await inRoute.addInRouteDetails(teste);
await inRoute.update(data);
return defaultResponse(inRoute);
} catch (error) {
return errorResponse(error.message, HttpStatus.UNPROCESSABLE_ENTITY);
}
}
This gives me this result on console:
Executing (default): UPDATE `InRoutesDetails` SET `InRouteId`=?,`updatedAt`=? WHERE `id` IN ('[object Object]')
He tries to compare id with some object.

Related

Sequelize seems to ignore associations with natural keys and/or adds additional fields

I have 2 situations. The main thing that connects them is that the primary keys on the tables are not autoincrement integers, which seems to cause sequelize to try to create additional association or field names.
Situation 1, I have 2 tables, I have the associations defined. When I try to query it, a random extra field gets inserted, throwing an error.
Model 1 file
const { DataTypes, Model } = require('sequelize');
const modelName = 'BusinessAccountSetting';
const tableName = 'BusinessAccountSettings';
class BusinessAccountSetting extends Model {
static doInit (sequelize) {
this.init({
_id: {
type: DataTypes.BIGINT.UNSIGNED,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
BusinessAccountId: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false
},
BusinessSettingKey: {
type: DataTypes.STRING(200),
allowNull: false,
defaultValue: true
},
value: {
type: DataTypes.JSON,
allowNull: false
}
}, {
sequelize,
modelName,
tableName,
timestamps: true,
paranoid: true
});
};
static associate (models) {
this.belongsTo(models.BusinessAccount, {
as: 'business',
foreignKey: 'BusinessAccountId',
targetKey: '_id'
});
this.belongsTo(models.BusinessSetting, {
as: 'setting',
foreignKey: 'BusinessSettingKey',
targetKey: 'BusinessSettingKey'
});
};
};
module.exports = {
modelName,
model: BusinessAccountSetting
};
Model 2 file
const { DataTypes, Model } = require('sequelize');
const modelName = 'BusinessSetting';
const tableName = 'BusinessSettings';
class BusinessSetting extends Model {
static doInit (sequelize) {
this.init({
BusinessSettingKey: {
type: DataTypes.STRING(200),
allowNull: false,
primaryKey: true,
unique: true
},
label: {
type: DataTypes.STRING(200),
allowNull: false
},
description: {
type: DataTypes.STRING(500),
allowNull: true
},
defaultValue: {
type: DataTypes.JSON,
allowNull: false
},
BusinessSettingGroupKey: {
type: DataTypes.STRING(200),
allowNull: false
},
order: {
type: DataTypes.SMALLINT.UNSIGNED,
allowNull: false
}
}, {
sequelize,
modelName,
tableName,
timestamps: true,
paranoid: true
});
};
static associate (models) {
this.belongsTo(models.BusinessSettingGroup, {
as: 'group',
foreignKey: 'BusinessSettingGroupKey',
targetKey: 'BusinessSettingGroupKey'
});
this.hasMany(models.BusinessAccountSetting, {
as: 'businessAccountSettings',
foreignKey: 'BusinessSettingKey',
sourceKey: 'BusinessSettingKey'
});
};
};
module.exports = {
modelName,
model: BusinessSetting
};
When I run this query
const settings = await sqldb.BusinessSetting.findAll({
include: [
{
model: sqldb.BusinessAccountSetting,
as: 'businessAccountSettings',
where: {
BusinessAccountId
},
required: false
}
]
});
It generates this sql
SELECT
`BusinessSetting`.`BusinessSettingKey`,
`BusinessSetting`.`label`,
`BusinessSetting`.`description`,
`BusinessSetting`.`defaultValue`,
`BusinessSetting`.`BusinessSettingGroupKey`,
`BusinessSetting`.`order`,
`BusinessSetting`.`createdAt`,
`BusinessSetting`.`updatedAt`,
`BusinessSetting`.`deletedAt`,
`businessAccountSettings`.`_id` AS `businessAccountSettings._id`,
`businessAccountSettings`.`BusinessAccountId` AS `businessAccountSettings.BusinessAccountId`,
`businessAccountSettings`.`BusinessSettingKey` AS `businessAccountSettings.BusinessSettingKey`,
`businessAccountSettings`.`value` AS `businessAccountSettings.value`,
`businessAccountSettings`.`createdAt` AS `businessAccountSettings.createdAt`,
`businessAccountSettings`.`updatedAt` AS `businessAccountSettings.updatedAt`,
`businessAccountSettings`.`deletedAt` AS `businessAccountSettings.deletedAt`,
`businessAccountSettings`.`BusinessSettingBusinessSettingKey` AS `businessAccountSettings.BusinessSettingBusinessSettingKey`
FROM
`BusinessSettings` AS `BusinessSetting` LEFT OUTER JOIN `BusinessAccountSettings` AS `businessAccountSettings` ON `BusinessSetting`.`BusinessSettingKey` = `businessAccountSettings`.`BusinessSettingKey`
AND (`businessAccountSettings`.`deletedAt` IS NULL AND `businessAccountSettings`.`BusinessAccountId` = 20)
WHERE (`BusinessSetting`.`deletedAt` IS NULL);
Which throws an error because of this:
`businessAccountSettings`.`BusinessSettingBusinessSettingKey` AS `businessAccountSettings.BusinessSettingBusinessSettingKey`
The associations are defined. The primary keys are defined. It should not be trying to add additional fields to fill in the blanks.
It's not an extra hook because it is trying to create a field for the reverse association which is already defined. It's not coming from another model association and I went through all of my files and remove the hooks: true flags just to be sure.
Problem #2, M:N associations with non-numeric keys
File #1
const { DataTypes, Model } = require('sequelize');
const modelName = 'BusinessRoleTemplate';
const tableName = 'BusinessRoleTemplates';
class BusinessRoleTemplate extends Model {
static doInit (sequelize) {
this.init({
BusinessRoleTemplateKey: {
type: DataTypes.STRING(100),
primaryKey: true,
allowNull: false,
unique: true
},
description: {
type: DataTypes.STRING(250),
allowNull: true
},
group: {
type: DataTypes.STRING(50),
allowNull: true
},
isCategoryTemplate: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
},
ranking: {
type: DataTypes.TINYINT.UNSIGNED,
allowNull: false
},
active: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true
}
}, {
sequelize,
modelName,
tableName,
timestamps: true,
paranoid: true
});
};
static associate (models) {
this.belongsToMany(models.BusinessPermission, {
as: 'permissions',
through: models.BusinessRoleTemplatePermission
});
};
};
module.exports = {
modelName,
model: BusinessRoleTemplate
};
File 2
const { DataTypes, Model } = require('sequelize');
const modelName = 'BusinessPermission';
const tableName = 'BusinessPermissions';
class BusinessPermission extends Model {
static doInit (sequelize) {
this.init({
BusinessPermissionKey: {
type: DataTypes.STRING(100),
allowNull: false,
primaryKey: true,
unique: true
},
plainText: {
type: DataTypes.STRING(100),
allowNull: false
},
description: {
type: DataTypes.STRING(250),
allowNull: true
},
requiresRank: {
type: DataTypes.INTEGER(2).UNSIGNED,
allowNull: false,
defaultValue: 10
},
BusinessPermissionGroupKey: {
type: DataTypes.STRING(100),
allowNull: false
},
isCategoryPermission: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
},
active: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true
}
}, {
sequelize,
modelName,
tableName,
timestamps: true,
paranoid: true
});
};
static associate (models) {
this.belongsTo(models.BusinessPermissionGroup, {
as: 'group',
foreignKey: 'BusinessPermissionGroupKey',
targetKey: 'BusinessPermissionGroupKey'
});
this.hasMany(models.BusinessPermissionAlternative, {
as: 'alternates',
foreignKey: 'AlternateBusinessPermissionKey',
sourceKey: 'BusinessPermissionKey'
});
this.belongsToMany(models.BusinessRoleTemplate, {
as: 'roleTemplates',
through: models.BusinessRoleTemplatePermission
});
this.belongsToMany(models.BusinessRole, {
as: 'roles',
through: models.BusinessRolePermission
});
};
};
module.exports = {
modelName,
model: BusinessPermission
};
Association table
const { DataTypes, Model } = require('sequelize');
const modelName = 'BusinessRoleTemplatePermission';
const tableName = 'BusinessRoleTemplatePermissions';
class BusinessRoleTemplatePermission extends Model {
static doInit (sequelize) {
this.init({
_id: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
BusinessPermissionKey: {
type: DataTypes.STRING(100),
allowNull: false
},
BusinessRoleTemplateKey: {
type: DataTypes.STRING(100),
allowNull: false
}
}, {
sequelize,
modelName,
tableName,
timestamps: true,
paranoid: false
});
};
static associate (models) {
this.belongsTo(models.BusinessPermission, {
as: 'permission',
foreignKey: 'BusinessPermissionKey',
targetKey: 'BusinessPermissionKey'
});
this.belongsTo(models.BusinessRoleTemplate, {
as: 'role',
foreignKey: 'BusinessRoleTemplateKey',
targetKey: 'BusinessRoleTemplateKey'
});
};
};
module.exports = {
modelName,
model: BusinessRoleTemplatePermission
};
BusinessRoleTemplate hasMany BusinessPermissions through BusinessRoleTemplatePermissions
BusinessRoleTemplatePermissions has the associations for both tables defined, so there shouldn't be a need for anything else.
However, when I run this query:
role = await sqldb.BusinessRoleTemplate.findOne({
where: {
BusinessRoleTemplateKey: data.role
},
attributes: ['BusinessRoleTemplateKey', 'description', 'isCategoryTemplate', 'ranking'],
include: [
{
model: sqldb.BusinessPermission,
as: 'permissions',
attributes: ['BusinessPermissionKey', 'isCategoryPermission']
}
]
});
I get this SQL:
SELECT
`BusinessRoleTemplate`.`BusinessRoleTemplateKey`,
`BusinessRoleTemplate`.`description`,
`BusinessRoleTemplate`.`isCategoryTemplate`,
`BusinessRoleTemplate`.`ranking`,
`permissions`.`BusinessPermissionKey` AS `permissions.BusinessPermissionKey`,
`permissions`.`isCategoryPermission` AS `permissions.isCategoryPermission`,
`permissions->BusinessRoleTemplatePermission`.`_id` AS `permissions.BusinessRoleTemplatePermission._id`,
`permissions->BusinessRoleTemplatePermission`.`BusinessPermissionKey` AS `permissions.BusinessRoleTemplatePermission.BusinessPermissionKey`,
`permissions->BusinessRoleTemplatePermission`.`BusinessRoleTemplateKey` AS `permissions.BusinessRoleTemplatePermission.BusinessRoleTemplateKey`,
`permissions->BusinessRoleTemplatePermission`.`createdAt` AS `permissions.BusinessRoleTemplatePermission.createdAt`,
`permissions->BusinessRoleTemplatePermission`.`updatedAt` AS `permissions.BusinessRoleTemplatePermission.updatedAt`,
`permissions->BusinessRoleTemplatePermission`.`BusinessPermissionBusinessPermissionKey` AS `permissions.BusinessRoleTemplatePermission.BusinessPermissionBusinessPermissionKey`,
`permissions->BusinessRoleTemplatePermission`.`BusinessRoleTemplateBusinessRoleTemplateKey` AS `permissions.BusinessRoleTemplatePermission.BusinessRoleTemplateBusinessRoleTemplateKey`
FROM `BusinessRoleTemplates` AS `BusinessRoleTemplate`
LEFT OUTER JOIN (
`BusinessRoleTemplatePermissions` AS `permissions->BusinessRoleTemplatePermission`
INNER JOIN `BusinessPermissions` AS `permissions`
ON `permissions`.`BusinessPermissionKey` = `permissions->BusinessRoleTemplatePermission`.`BusinessPermissionBusinessPermissionKey`)
ON `BusinessRoleTemplate`.`BusinessRoleTemplateKey` = `permissions->BusinessRoleTemplatePermission`.`BusinessRoleTemplateBusinessRoleTemplateKey`
AND (`permissions`.`deletedAt` IS NULL)
WHERE (`BusinessRoleTemplate`.`deletedAt` IS NULL AND `BusinessRoleTemplate`.`BusinessRoleTemplateKey` = 'Senior Manager');
With all sorts of stuff added:
added fields:
`permissions->BusinessRoleTemplatePermission`.`BusinessPermissionBusinessPermissionKey` AS `permissions.BusinessRoleTemplatePermission.BusinessPermissionBusinessPermissionKey`,
`permissions->BusinessRoleTemplatePermission`.`BusinessRoleTemplateBusinessRoleTemplateKey` AS `permissions.BusinessRoleTemplatePermission.BusinessRoleTemplateBusinessRoleTemplateKey`
Added associations:
ON `permissions`.`BusinessPermissionKey` = `permissions->BusinessRoleTemplatePermission`.`BusinessPermissionBusinessPermissionKey`)
If I change the association in BusinessRoleTemplate to this, it works:
this.belongsToMany(models.BusinessPermission, {
as: 'permissions',
through: models.BusinessRoleTemplatePermission,
foreignKey: 'BusinessRoleTemplateKey',
otherKey: 'BusinessPermissionKey'
});
I shouldn't need to add the foreignKey and otherKey because the associations are already defined in the through table, but sequelize isn't recognizing them, it is trying to create them.

sequelize many to many not working correcttly with a legacy databse

I've got an existing mysql database where i've got the following tables : category,product and product_category.I've used sequelizer-auto package to generate models from the 3 tables like the following:
Product.js ,model generated from product table:
module.exports = function(sequelize, DataTypes) {
const Product= sequelize.define('product', {
productId: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true,
field: 'product_id'
},
name: {
type: DataTypes.STRING(100),
allowNull: false,
field: 'name'
},
description: {
type: DataTypes.STRING(1000),
allowNull: false,
field: 'description'
},
price: {
type: DataTypes.DECIMAL,
allowNull: false,
field: 'price'
},
discountedPrice: {
type: DataTypes.DECIMAL,
allowNull: false,
defaultValue: '0.00',
field: 'discounted_price'
},
image: {
type: DataTypes.STRING(150),
allowNull: true,
field: 'image'
},
image2: {
type: DataTypes.STRING(150),
allowNull: true,
field: 'image_2'
},
thumbnail: {
type: DataTypes.STRING(150),
allowNull: true,
field: 'thumbnail'
},
display: {
type: DataTypes.INTEGER(6),
allowNull: false,
defaultValue: '0',
field: 'display'
}
}, {
tableName: 'product'
});
Product.associate=(models)=>{
Product.belongsToMany(models.category,{
through:'product_category',
foreignkey:'product_id',
as:'categories'
})
}
return Product;
};
Category.js generated from 'category table'
module.exports = function(sequelize, DataTypes) {
const Category= sequelize.define('category', {
categoryId: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true,
field: 'category_id'
},
departmentId: {
type: DataTypes.INTEGER(11),
allowNull: false,
field: 'department_id'
},
name: {
type: DataTypes.STRING(100),
allowNull: false,
field: 'name'
},
description: {
type: DataTypes.STRING(1000),
allowNull: true,
field: 'description'
}
},
{
tableName: 'category',
});
Category.associate=(models)=>{
Category.belongsToMany(models.Product, {
through: 'product_category',
foreignkey: 'category_id',
as: 'products'
});
}
return Category;
};
ProductCategory from product_category table
module.exports = function(sequelize, DataTypes) {
return sequelize.define('product_category', {
productId: {
type: DataTypes.INTEGER(11),
references:{
key:'product_id',
model:'product'
}
},
categoryId: {
type: DataTypes.INTEGER(11),
references:{
key: 'category_id',
model:'category'
}
}
}, {
tableName: 'product_category'
});
};
And here is the category controller categories.js:
const db=require('../services/db_init');
const DataTypes=require('sequelize').DataTypes;
const Category=require('../database/models/Category')(db,DataTypes);
const Product=require('../database/models/Product')(db,DataTypes);
const {category_errors:{cat_01,cat_02}} = require('../services/errors.js');
//test code
const Product = require('../database/models/Product')(db,DataTypes);
module.exports=(app)=>{
app.get('/categories',async(req,res)=>{
try {
const categories = await Category.findAll({
include:{
model:Product,
as:'products'
}
});
return res.send(categories).status(200);
} catch (err) {
return res.json({error:err}).status(400);
}
});
app.get('/categories/:id',async(req,res)=>{
const id=req.params.id;
//checking if the id is a number
if(isNaN(id)){
return res.json({error:cat_01})//error returned
}
try {
const category=await Category.findByPk(id);
if(category){
return res.send(category).status(200);
}
return res.json({error:cat_02}).status(404);
} catch (err) {
return res.json(err).status(400);
}
});
}
All methode are working as expected,but after adding relashionship between models i've got some problems.First in GET /categories ,the implementation of the query was const categories = await Category.findAll() and everything was working fine,but after changing the implementation to const categories = await Category.findAll({include:{model:Product,as:'products'}}); i get the follwing error {
"error": {
"name": "SequelizeEagerLoadingError"
}
}
I've tried to read many topics,and solutions but i always have the same issue

Unable to insert id into a table that belongs to a foreign key referenced table using Sequelize

I am building serverless application using node js and using claudia-api-builder as a framework to launch APIs in AWS.
In app.js file, i call the required api as
const ApiBuilder = require('claudia-api-builder');
const api = new ApiBuilder();
module.exports = api;
api.post('/api/auth/validatephonenumber', async function (request)
{
return new Promise((resolve, reject) => {
index.loadDatabase().then((db) => {
resolve(loginController.validatePhonenumber(db, request));
});
});
});
Below is my code:
async function validatePhonenumber(db, request) {
return new Promise(
async (resolve, reject) => {
let emailid;
await db.EmailRegistration.sync().then(function () {
emailid = db.EmailRegistration.findOne({
where: { email: { [Op.eq]: mailid } },
attributes: ['id'],
});
});
if (emailid != null) {
console.log(`email id: ${emailid.id}`);
await db.ContactDetails.sync().then(function () {
db.ContactDetails.findOrCreate({
where: { contactnumber: phnum },
defaults: { EmailRegistrationId: emailid.id },
}).spread((contactdetails, created) => {
console.log(`contactdetails: ${contactdetails}`);
if (contactdetails !== null) {
resolve({ statuscode: indexController.statusCode.statusOK, contactdetails: contactdetails })
} else {
reject({ statuscode: indexController.statusCode.InternalServerError, message: 'phone number not created' });
}
});
});
};
});
}
I am trying to add a emailregistrationid of EmailRegistration table into ContactDetails table as a foreign key reference. I am using sequelize with mysql, nodejs to achieve the desired results. But, i am getting below error:
Unhandled rejection SequelizeForeignKeyConstraintError: Cannot add or update a child row: a foreign key constraint fails (inmeeydb.ContactDetails, CONSTRAINT ContactDetails_ibfk_1 FOREIGN KEY (EmailRegistrationId) REFERENCES EmailRegistration (id) ON DELETE CASCADE ON UPDATE CASCADE)
Below is my EmailRegistration models file:
const moment = require('moment');
module.exports = (sequelize, DataTypes) => {
const EmailRegistration = sequelize.define(
'EmailRegistration',
{
id: {
type: DataTypes.UUID,
primaryKey: true,
allowNull: false,
defaultValue: DataTypes.UUIDV4,
},
email: {
type: DataTypes.STRING(50),
allowNull: false,
},
password: {
type: DataTypes.STRING,
allowNull: false,
validate: { min: 6 },
},
createdAt: {
type: DataTypes.DATE,
get() {
return moment.utc(new Date(), 'DD/MM/YYYY h:mm a').format('DD/MM/YYYY h:mm a');
},
},
updatedAt: {
type: DataTypes.DATE,
defaultValue: null,
},
},
{
freezeTableName: true,
}
);
EmailRegistration.associate = function (models) {
EmailRegistration.hasOne(models.ContactDetails,
{ foreignKey: 'EmailRegistrationId' }
);
};
return EmailRegistration;
};
Below is my Contactdetails models file:
const moment = require('moment');
module.exports = (sequelize, DataTypes) => {
const ContactDetails = sequelize.define(
'ContactDetails',
{
id: {
type: DataTypes.UUID,
primaryKey: true,
allowNull: false,
defaultValue: DataTypes.UUIDV4,
},
contactnumber: { type: DataTypes.STRING(13), allowNull: false },
isverified: { type: DataTypes.BOOLEAN, defaultValue: false },
createdAt: {
type: DataTypes.DATE,
get() {
return moment.utc(new Date(), 'DD/MM/YYYY h:mm a').format('DD/MM/YYYY h:mm a');
},
},
updatedAt: {
type: DataTypes.DATE,
defaultValue: null,
},
},
{
indexes: [{ fields: ['contactnumber'], unique: true }],
},
{
freezeTableName: true,
}
);
ContactDetails.associate = function(models) {
ContactDetails.belongsTo(models.EmailRegistration, {
onDelete: 'CASCADE',
hooks: true,
foreignKey: { allowNull: false },
});
};
return ContactDetails;
};
I tried to change the code as below with reference in both tables, but nothing worked.
ContactDetails.associate = function(models) {
ContactDetails.belongsTo(models.EmailRegistration,
{ foreignKey: 'EmailRegistrationId' }
);
};
Not able to analyze how to overcome the issue. This worked fine when i used nodejs with expressjs and had no issues. It fails to identify the EmailRegistrationId(that is missing in the query) in ContactDetails table and shows the output as
INSERT INTO `ContactDetails` (`id`,`contactnumber`,`isverified`,`createdAt`,`updatedAt`) VALUES ('52974e07-8489-4101-ab71-6af874903290','+xxxxxxxxx',false,'2018-10-12 08:55:35','2018-10-12 08:55:35');
You need to update the configuration of your association. The ContactDetails model will now have a field called emailregistrationid
EmailRegistration.associate = function (models) {
EmailRegistration.hasMany(models.ContactDetails);
};
ContactDetails.associate = function(models) {
ContactDetails.belongsTo(models.EmailRegistration, {
onDelete: 'CASCADE',
hooks: true,
foreignKey: {
name: 'emailregistrationid'
allowNull: false
},
});
}
ContactDetails.create({
...
emailregistrationid: <some_valid_emailregistrationid>
})

Sequelize get values from belongsTo relationship

I am creating an app using an existing database in Mysql.
I can retrieve the values from the tables, but when I try to retrieve the values from associate models, doesn't work.
Purchase Order model:
"use strict";
module.exports = (sequelize, DataTypes) => {
var PurchaseOrder = sequelize.define('purchase_orders' , {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true,
field: 'id'
},
purchaseDate: {
type: DataTypes.DATE,
allowNull: true,
field: 'purchase_date'
},
supplierId: {
type: DataTypes.INTEGER(11),
allowNull: true,
// references: {
// model: 'suppliers',
// key: 'id'
// },
field: 'supplier_id'
},
requestedById: {
type: DataTypes.INTEGER(11),
allowNull: true,
field: 'requested_by_id'
},
masterPurchaseOrderId: {
type: DataTypes.INTEGER(11),
allowNull: true,
// references: {
// model: 'master_purchase_orders',
// key: 'id'
// },
field: 'master_purchase_order_id'
},
createdAt: {
type: DataTypes.DATE,
allowNull: false,
field: 'created_at'
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false,
field: 'updated_at'
}
},{
classMethods:{
associate: (models) => {
PurchaseOrder.belongsTo(models.masterPurchaseOrders,{
foreignkey: 'master_purchase_order_id'
});
},
associate: (models) => {
PurchaseOrder.belongsTo(models.supplier,{
foreignkey: 'supplier_id'
});
},
},
}, {
timestamps: true,
paranoid: false,
underscored: true,
freezeTableName: true,
tableName: 'purchase_orders'
});
return PurchaseOrder;
}
Purchase Order Controller:
"using strict";
const purchaseOrder = require('../models/').purchase_orders;
const Supplier = require('../models/').supplier;
const Master = require('../models/').masterPurchaseOrders;
module.exports= {
index(req, res) {
purchaseOrder
.findAll({
include:[Supplier, Master]
})
.then((masters) => {
res.status(200).json(masters);
})
.catch((error) => {
res.status(500).json(error);
});
},
create(req, res) {
purchaseOrder
.create(req.body)
.then( master => {
res.status(200).json(master);
})
.catch( error => {
res.status(500).json(error);
});
},
};
If I only include the model supplier in the function findall(). I get the data from the purchase and the data from the supplier.
But when I include the model master purchase order. I get an empty json.
Can you do the following
purchaseOrder
.findAll({
include:[{model: Supplier, required:true}, {model: Master, required : false}]
})
It's because you overwrite the associate property of your classMethods, and only the second associate() function will be executed.
You should move both of your association definitions into one function:
classMethods:{
associate: (models) => {
PurchaseOrder.belongsTo(models.masterPurchaseOrders,{
foreignkey: 'master_purchase_order_id'
});
PurchaseOrder.belongsTo(models.supplier,{
foreignkey: 'supplier_id'
});
},
},

Sequelize says instanceMethod is not defined

I'm using sequelize to connect to a mysql db for development. I have a model called Dealer:
'use strict';
module.exports = function(sequelize, DataTypes) {
var Dealer = sequelize.define('Dealer', {
id: { allowNull: false, autoIncrement: true,
primaryKey: true, type: DataTypes.INTEGER.UNSIGNED },
...
created_at: { allowNull: false, type: DataTypes.DATE },
updated_at: { allowNull: false, type: DataTypes.DATE }
},
{underscored: true},
{
classMethods: {
associate: function(models) {
Dealer.hasMany(models.Job);
}
},
instanceMethods: {
getAllClientData: function(){
leads = [];
...
return leads;
},
}
});
return Dealer;
};
When I try to call the instance method on an object returned by a sequelize query in my dealerController.js file:
dealer.getAllClientData()
I get the error:
Unhandled rejection TypeError: dealer.getAllClientData is not a function
When i print the returned JSON to the console it reads as such:
{ dataValues:
{ id: 1,
....
}
...
'$modelOptions':
{ timestamps: true,
instanceMethods: {},
classMethods: {},
validate: {},
freezeTableName: false,
underscored: true,
underscoredAll: false,
paranoid: false,
rejectOnEmpty: false,
whereCollection: { id: '1' },
schema: null,
schemaDelimiter: '',
defaultScope: {},
scopes: [],
hooks: {},
indexes: [],
name: { plural: 'Dealers', singular: 'Dealer' },
omitNul: false,
...
}
...
}
Obviously my instanceMethod is not defined, and according to the sequelize docs I should have getters and setters available too.
I don't understand what step i'm missing here as I've read through much of the sequelize docs and even used their cli to generate the models and migrations.
Any thoughts?
Edit:
Here is what is output to log for dealer.prototype
{ _customGetters: {},
_customSetters: {},
validators: {},
_hasCustomGetters: 0,
_hasCustomSetters: 0,
rawAttributes:
{ id:
{ allowNull: false,
autoIncrement: true,
primaryKey: true,
type: [Object],
Model: Dealer,
fieldName: 'id',
_modelAttribute: true,
field: 'id' },
///Other Attributes
},
_isAttribute: { [Function] cache: MapCache { __data__: [Object] } },
Model: Dealer,
$Model': Dealer }
After reading the docs a little further and looking at some other model definitions I discovered that the issue was I had defined my model incorrectly.
In my definition above you'll notice I wrapped the underscored: true option in brackets, followed by my classMethods and instanceMethods wrapped in another set of brackets.
This is incorrect. The proper way to define a sequelize model is with two sets of brackets, the first containing your model attributes and the second containing all other options, including methods.
'use strict';
module.exports = function(sequelize, DataTypes) {
var Dealer = sequelize.define('Dealer', {
id: { allowNull: false, autoIncrement: true,
primaryKey: true, type: DataTypes.INTEGER.UNSIGNED },
...
created_at: { allowNull: false, type: DataTypes.DATE },
updated_at: { allowNull: false, type: DataTypes.DATE }
},
{
underscored: true,
classMethods: {
associate: function(models) {
Dealer.hasMany(models.Job);
}
},
instanceMethods: {
getAllClientData: function(){
leads = [];
...
return leads;
},
}
});
return Dealer;
};