Sequelize error : cannot find property "startYear" of undefined - node.js

I am using sequelize cli and got each migration file for each model generated, I am trying to generate all the tables with a single migration file as they are dependent on each other, but I am keep getting this error
cannot find property startYear of undefined
Also, I need a tutorial on how to change models in sequelize using sequelize cli.
"use strict";
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface
.createTable("Users", {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
googleId: {
allowNull: true,
type: Sequelize.STRING
},
facebookId: {
allowNull: true,
type: Sequelize.STRING
},
fullName: {
type: Sequelize.STRING,
allowNull: false
},
email: {
type: Sequelize.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: true
}
},
password: {
type: Sequelize.STRING,
allowNull: false,
validate: {
isAlphanumeric: true,
notEmpty: true
}
},
isVerified: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
})
.then(function() {
return queryInterface
.createTable("DesignationMasters", {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
designationName: {
type: Sequelize.STRING,
allowNull: false,
unique: true
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
})
.then(function() {
return queryInterface
.createTable("companyDetails", {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
companyName: {
type: Sequelize.STRING,
allowNull: true,
defaultValue: null
},
userId: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: "Users",
key: "id"
}
},
designationId: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: "DesignationMasters",
key: "id"
}
},
startYear: {
type: Sequelize.INTEGER,
validate: {
isNumeric: true,
len: [4, 4]
},
defaultValue: null
},
endYear: {
type: Sequelize.INTEGER,
validate: {
isNumeric: true,
len: [4, 4],
min: this.startYear
},
defaultValue: null
},
isCurrentWorkplace: {
type: Sequelize.BOOLEAN,
defaultValue: false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
})
.then(function() {
return queryInterface
.createTable("InterestMasters", {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
interestValue: {
allowNull: false,
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
})
.then(function() {
return queryInterface.createTable("UserInterests", {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
userId: {
type: Sequelize.INTEGER,
references: {
model: "Users",
key: "id"
},
allowNull: false
},
interestId: {
type: Sequelize.INTEGER,
references: {
key: "InterestMasters",
value: "id"
},
allowNull: false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
});
});
});
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable("InterestMasters").then(function() {
return queryInterface.dropTable("Interests").then(function() {
return queryInterface.dropTable("companyDetails").then(function() {
return queryInterface
.dropTable("DesignationMasters")
.then(function() {
return queryInterface.dropTable("Users");
});
});
});
});
}
};

Use a validate function in the options argument:
{
validate: {
endYearIsAtLeastStartYear() {
if (this.endYear < this.startYear) {
throw new Error('End year must be equal to or higher than start year')
}
}
}

Related

sequelize Bulk insert fails when seeding

I am using sequelize as ORM in a node project and trying to insert some seed data, however, that fails.
I am trying to find a way so the insert statement generated by sequelize either ignores the Id or Accepts the Id I am setting and before the insert statement sets the SET IDENTITY_INSERT TO ON and then after inserting sets is to off.
I know setting the needIdentityInsertWrapper:true does the latter but there is something wrong in my syntax it seems.
following is the model
module.exports = (sequelize, DataTypes) => {
const Client = sequelize.define("Client", {
Id: {
primaryKey: true,
type: "INTEGER IDENTITY(1,1)",
},
Name:{
type: "VARCHAR(250)",
allowNull: false,
validate: {
notEmpty: true
}
},
AddressLine1:{
type: "VARCHAR(500)",
allowNull: false,
validate: {
notEmpty: true
}
},
AddressLine2:{
type: "VARCHAR(500)",
allowNull: true,
},
AddressLine3:{
type: "VARCHAR(500)",
allowNull: true,
},
Postcode:{
type: "VARCHAR(10)",
allowNull: false,
validate: {
notEmpty: true
}
},
City:{
type: "VARCHAR(100)",
allowNull: true,
},
County:{
type: "VARCHAR(50)",
allowNull: true,
},
Country:{
type: "VARCHAR(100)",
allowNull: true,
},
ContactNumber : {
type: "VARCHAR(20)",
allowNull: true,
},
Email : {
type: "VARCHAR(500)",
allowNull: true,
},
CreatedAt :{
type:"datetimeoffset(7) DEFAULT GETDATE()",
allowNull: false
},
UpdatedAt :{
type:"datetimeoffset(7)",
allowNull: true
}
},
{freezeTableName: true, createdAt: false,updatedAt: false}
);
Client.associate=models=>{
Client.hasMany(models.Invoice,{foreignKey:"ClientId"})
}
return Client;
}
and here is the bulk insert code
var db = require('../models')
module.exports = async function () {
return await db.Client.bulkCreate(
[{
// Id:1,
name:"Company",
AddressLine1:"Add 1",
Postcode:"Postcode",
City:"UK"
}],{},
{
autoincrement :true,
needIdentityInsertWrapper:true
}
)
}
To fix the issue I made the following code change
module.exports = (sequelize, DataTypes) => {
const Client = sequelize.define("Client", {
Id: {
primaryKey: true,
type: "INTEGER",
autoIncrement:true
},
Name:{
type: "VARCHAR(250)",
allowNull: false,
validate: {
notEmpty: true
}
},
AddressLine1:{
type: "VARCHAR(500)",
allowNull: false,
validate: {
notEmpty: true
}
},
AddressLine2:{
type: "VARCHAR(500)",
allowNull: true,
},
AddressLine3:{
type: "VARCHAR(500)",
allowNull: true,
},
Postcode:{
type: "VARCHAR(10)",
allowNull: false,
validate: {
notEmpty: true
}
},
City:{
type: "VARCHAR(100)",
allowNull: true,
},
County:{
type: "VARCHAR(50)",
allowNull: true,
},
Country:{
type: "VARCHAR(100)",
allowNull: true,
},
ContactNumber : {
type: "VARCHAR(20)",
allowNull: true,
},
Email : {
type: "VARCHAR(500)",
allowNull: true,
},
CreatedAt :{
type:"datetimeoffset(7) DEFAULT GETDATE()",
allowNull: false
},
UpdatedAt :{
type:"datetimeoffset(7)",
allowNull: true
}
},
{freezeTableName: true, createdAt: false,updatedAt: false}
);
Client.associate=models=>{
Client.hasMany(models.Invoice,{foreignKey:"ClientId"})
}
return Client;
}

Sequelize hasMany assocaition

I am considering these 2 tables "exam_response" and "answer" for hasMany association.
Where both the tables contains "question_id". Using question_id I need the answers.
exam_response table
module.exports = (sequelize, DataTypes) => {
const exam_response = sequelize.define('exam_response', {
id: {
allowNull: false,
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4
},
session_id: {
type: DataTypes.UUID,
allowNull: false
},
exam_id: {
type: DataTypes.UUID,
allowNull: false
},
user_id: {
type: DataTypes.UUID,
allowNull: false
},
question_id: {
type: DataTypes.UUID,
allowNull: false
},
answer_ids: {
type: DataTypes.ARRAY(DataTypes.UUID),
allowNull: false
},
is_correct: {
type: DataTypes.BOOLEAN,
allowNull: false
},
is_bookmarked: {
type: DataTypes.BOOLEAN,
allowNull: false
},
is_attempted: {
type: DataTypes.BOOLEAN,
allowNull: false
},
createdAt: {
type: DataTypes.DATE,
field: 'created_at'
},
updatedAt: {
type: DataTypes.DATE,
field: 'updated_at'
}
}, {});
exam_response.associate = function (models) {
// associations can be defined here
exam_response.hasMany(models.answer, {
foreignKey: 'question_id', sourceKey: 'question_id',as:'exam_answers'
});
};
answer table
'use strict';
module.exports = (sequelize, DataTypes) => {
const answer = sequelize.define('answer', {
//{
// "id":"",
// "question_id":"123",
// "position":0,
// "answer":"This is answer 1."
// }
id: {
allowNull: false,
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4
},
question_id: {
allowNull: false,
type: DataTypes.UUID
},
position: {
allowNull: false,
type: DataTypes.INTEGER
},
answer: {
allowNull: false,
type: DataTypes.TEXT
},
publish_status: {
allowNull: false,
type: DataTypes.ENUM('published', 'unpublished', 'deleted')
},
language: {
type: DataTypes.ENUM('en', 'kn', 'hi')
},
createdAt: {
type: DataTypes.DATE,
field: 'created_at'
},
updatedAt: {
type: DataTypes.DATE,
field: 'updated_at'
}
}, {});
answer.associate = models => {
answer.belongsTo(models.question,{foreignKey:'question_id',as:'answers'});
answer.belongsTo(models.exam_response,{foreignKey:'question_id', targetKey: 'question_id',as:'exam_answers'});
};
return answer;
};
Query::
ExamResponse.findAll({
where: {
exam_id
},
include: [
{
model: Answer,as:'exam_answers'
}
],
}).then(resp => {
response.successGet(res, resp, 'Exam Response');
}).catch(next)
I am getting the output but associated part("exam_answers") is empty.
If I use raw query, i am able to get the output. But the Query is only fetching me the exam_response not the answer even though the value exists.

Sequelize - How to define ON DELETE action during model definition

I would like to ask you if it is possible to set ON DELETE action while defining a Sequelize model, for example:
sequelize.define('oAuthAccessTokens', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
createdAt: Sequelize.DATE,
updatedAt: Sequelize.DATE,
accessToken: { type: Sequelize.STRING(256), allowNull: false },
expires: { type: Sequelize.DATE, allowNull: false },
scope: Sequelize.STRING(255),
clientId: {
type: Sequelize.STRING(80),
allowNull: false,
references: {
model: 'oAuthClients',
key: "clientId",
**onDelete: "cascade"** // here is my try
}
},
userId: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'oAuthUsers',
key: "id",
**onDelete: "cascade"** // here is my try
}
}
});
I know it's possible to pass a proper option to hasOne() method, but what about such a model definition? I hope there is a way which is not mentioned in the official documentation.
Updated
The problem is solved now. The onDelete attribute should be outside the references one.
sequelize.define('oAuthAccessTokens', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
createdAt: Sequelize.DATE,
updatedAt: Sequelize.DATE,
accessToken: { type: Sequelize.STRING(256), allowNull: false },
expires: { type: Sequelize.DATE, allowNull: false },
scope: Sequelize.STRING(255),
clientId: {
type: Sequelize.STRING(80),
allowNull: false,
onDelete: "cascade",
references: {
model: 'oAuthClients',
key: "clientId",
}
},
userId: {
type: Sequelize.INTEGER,
onDelete: "cascade",
allowNull: false,
references: {
model: 'oAuthUsers',
key: "id"
}
}
});
The problem is solved now. The onDelete attribute should be outside the references one.
sequelize.define('oAuthAccessTokens', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
createdAt: Sequelize.DATE,
updatedAt: Sequelize.DATE,
accessToken: { type: Sequelize.STRING(256), allowNull: false },
expires: { type: Sequelize.DATE, allowNull: false },
scope: Sequelize.STRING(255),
clientId: {
type: Sequelize.STRING(80),
allowNull: false,
onDelete: "cascade",
references: {
model: 'oAuthClients',
key: "clientId",
}
},
userId: {
type: Sequelize.INTEGER,
onDelete: "cascade",
allowNull: false,
references: {
model: 'oAuthUsers',
key: "id"
}
}
});

How to create an associated object in Sequelize / Node.js ?

There is 2 models:
sequelize.define('Hotel', {
id: {
autoIncrement: true,
type: DataTypes.INTEGER,
primaryKey: true
},
latitude: {
type: DataTypes.DOUBLE,
allowNull: false
},
longitude: {
type: DataTypes.DOUBLE,
allowNull: false
},
title: {
type: DataTypes.STRING,
allowNull: false
},
description: {
type: DataTypes.TEXT,
allowNull: false
},
rating: {
type: DataTypes.DOUBLE,
defaultValue: 0
},
image: {
type: DataTypes.STRING
}
}, {
classMethods: {
associate: function(db) {
Hotel.hasMany(db.Comment, {
foreignKey: 'commentable_id',
scope: {
commentable: 'hotel'
}
});
}
}
});
And
sequelize.define('Comment', {
id: {
type: DataTypes.INTEGER,
primaryKey: true
},
content: {
type: DataTypes.TEXT,
allowNull: false
},
commentable: DataTypes.STRING,
commentable_id: DataTypes.INTEGER
});
How can I create associated Comment for existing Hotel instance? For example, I've tried:
hotel.addComment(request.models.Comment.create({content: 'content'}))
But it doesn't work. Please, tell me, how I can fix it? Thanks in advance!
request.models.Comment.create() is async, in other words it returns a promise that must be fullfilled before you can use the resolved value to 'feed' the addComment method.
So you should do something like
request.models.Comment.create({content: 'content'}).
then(function(comment){
return hotel.addComment(comment);
});

Sequelize saving many to many

I was wandering if there are any extended tutorials on how to save a many to many relationship? I find the documentation more than basic. Its missing many use case examples.
I have two models: Client and Rule. They have the n:n relationship.
Client:
var Client = sequelize.define('client', {
title: {
type: DataTypes.STRING(200),
allowNull: false
},
company: {
type: DataTypes.STRING(200),
allowNull: false
},
vendor: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
},
consumer: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true
},
address_id: {
type: DataTypes.INTEGER,
allowNull: true
}
},{
paranoid: true,
underscored: true,
classMethods: {
associate:function(models){
Client.hasMany(models.rule, { through: 'client_rules', onDelete: 'cascade'});
}
}
});
Rule:
var Rule = sequelize.define('rule', {
service_id: {
type: DataTypes.INTEGER,
allowNull: false
},
is_allowed: {
type: DataTypes.BOOLEAN,
defaultValue: false
},
valid_until: {
type: DataTypes.DATE,
allowNull: true,
},
rule: {
type: DataTypes.TEXT,
allowNull: true
},
type: {
type: DataTypes.INTEGER, // 1 for company rule, 2 for individual rule
allowNull: false,
},
active: {
type: DataTypes.BOOLEAN,
defaultValue: true
}
},{
underscored: true,
paranoid: true,
classMethods: {
associate:function(models){
Rule.belongsToMany(models.client, { through: 'client_rules', onDelete: 'cascade'});
Rule.belongsTo(models.service, { foreignKey: 'service_id' } );
}
}
});
Now I would like to create a new rule for client. So I would have to create the rule first and associate it then to the client through 'client_rules'.
How do I do that with sequelize? This doesn't work:
var clientID = req.user.client_id;
Client.find({ id: clientID })
.then(function(client){
return client.addRule(req.body)
})
.catch(function(err){
console.log(err)
})
[TypeError: Cannot read property 'replace' of undefined]
Ok I found out how to do it. The docs are very confusing.
var clientID = req.user.client_id;
return Rule.create(req.body)
.then(function(newRule){
var ruleToAdd = newRule;
return Client.findOne({ where: { id: clientID } })
.then(function(client){
return client.addRule(ruleToAdd)
.then(function(ans){
return ruleToAdd;
})
})

Resources