sequelize Bulk insert fails when seeding - node.js

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;
}

Related

Sequelize: Association with alias does not exist

I am using sequelize as ORM in a node project and running into some issues when querying.
Below is the code for the sequelize models in question. The table names are singular--see the use of freezable: true in the model. But when I use include it does not work and fails with the following error message
Error: Association with alias "Client" does not exist on Invoice
Model - client
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;
}
Model Invoice
module.exports = (sequelize, DataTypes) => {
const Invoice = sequelize.define("Invoice", {
Id: {
primaryKey: true,
type: "INTEGER",
autoIncrement:true
},
ClientId: {
type: DataTypes.INTEGER,
},
CompanyId: {
type: DataTypes.INTEGER,
},
InvoiceNumber:{
type: "VARCHAR(10)",
allowNull: false,
validate: {
notEmpty: true
}
},
InvoiceDate : {
type: DataTypes.DATEONLY,
},
Total: {
type: DataTypes.DECIMAL(18,2),
allowNull: true
},
CreatedAt :{
type:"datetimeoffset(7) DEFAULT GETDATE()",
allowNull: false
},
UpdatedAt :{
type:"datetimeoffset(7)",
allowNull: true
}
},
{freezeTableName: true, createdAt: false,updatedAt: false} );
Invoice.associate=models=>{
Invoice.belongsTo(models.Client,{
foreignKey:{
name:"ClientId",
allowNull:false
}
})
};
Invoice.associate=models=>{
Invoice.belongsTo(models.Company,{
foreignKey:{
name:"CompanyId",
allowNull:false
}
})
}
Invoice.associate=models=>{
Invoice.hasMany(models.InvoiceDetails,{foreignKey:"InvoiceId"})
}
return Invoice;
}
Query
let invoiceResult= await db.Invoice.findOne({where: {"InvoiceNumber":"INV001"}
,include:"Client"});
The above query does not work. However, the following one works
let invoiceResult= await db.Invoice.findOne({where: {"InvoiceNumber":"INV001"}
,include:"InvoiceDetails"});
The model for InvoiceDetails is as follows
module.exports = (sequelize, DataTypes) => {
const InvoiceDetails = sequelize.define("InvoiceDetails", {
Id: {
primaryKey: true,
type: "INTEGER",
autoIncrement:true
},
InvoiceId: {
type: DataTypes.INTEGER,
},
Description:{
type: DataTypes.STRING(500),
allowNull: false,
validate: {
notEmpty: true
}
},
Quantity:{
type: DataTypes.INTEGER,
allowNull: false,
validate: {
notEmpty: true
}
},
AmountPerUnit : {
type: DataTypes.DECIMAL(18,2),
allowNull: false,
validate: {
notEmpty: true
}
},
SubTotal: {
type: DataTypes.DECIMAL(18,2),
allowNull: false,
validate: {
notEmpty: true
}
},
VatPercentage: {
type: DataTypes.DECIMAL(5,2),
allowNull: false,
validate: {
notEmpty: true
}
},
VatAmount: {
type: DataTypes.DECIMAL(18,2),
allowNull: false,
validate: {
notEmpty: true
}
}
,
CreatedAt :{
type:"datetimeoffset(7) DEFAULT GETDATE()",
allowNull: false
},
UpdatedAt :{
type:"datetimeoffset(7)",
allowNull: true
}
},
{freezeTableName: true, createdAt: false,updatedAt: false}
);
InvoiceDetails.associate=models=>{
InvoiceDetails.belongsTo(models.Invoice,{
foreignKey:{
name:"InvoiceId",
allowNull:false
}
})
}
return InvoiceDetails;
}
Any pointers will be much appreciated.
i fixed it with the following changes
in the client model changed the following
Client.associate=models=>{
Client.hasMany(models.Invoice,{as:'Invoice',foreignKey:"ClientId"})
}
and in the invoice model
Invoice.associate=models=>{
Invoice.belongsTo(models.Client,{
as: 'Client',
foreignKey:{
name:"ClientId",
allowNull:false
}
})
};
After this change both the following queries work. The point being when using include as alias needs to be present in both the models. Atleast that's how I got it working.
let invoiceResult= await db.Invoice.findOne({where: {"InvoiceNumber":invoiceNumber}
,include:[
"Client"
]
});
let client= await db.Client.findAll({include:[
"Invoice"
]
});
Thanks for the help and taking the time to post an answer
I think this two way can help you
1:
Sequelize pluralized models try "Clients" instead
let invoiceResult= await db.Invoice.findOne({where: {"InvoiceNumber":"INV001"}
,include:"Clients"});
2: if "Clients" not work try this
let invoiceResult= await db.Invoice.findOne({where: {"InvoiceNumber":"INV001"}
,include:[{model: Client, as: "client"}]});
When using the "include" option in a query, you need to include a model object and not just the name of the table/model.
As an example I'll use a mock controller "InvoiceController.js":
const {Invoice} = require("Path to the invoice model") // or = 'db.Invoice'
const {Client} = require("Path to the client model") // or '= db.Client'
module.exports = {
async indexInvoiceWithClient (req, res) {
try {
let invoiceResults = await Invoice.findOne({
where: {
InvoiceNumber: "INV001" // req.query.invoiceNum if you request it over http/s
},
include: {
model: Client
}
})
console.log(invoiceResults)
res.status(200).send(invoiceResults)
} catch (err) {
console.log(err)
res.status(500).send({
error: "An error occured while fetching the clients on this Invoice etc..."
})
}
}
}

Why does associating belongsTo in Sequelize give me this error?

I'm stuck with this problem for quite some time now and I don't know what's wrong with my code I'm trying to associate one table to another but only half of it works any help would be greatly appreciated.
models/companies.js
const DataTypes = require('sequelize');
const sequelize = require('../config/database');
const Users = require('./users');
const Companies = sequelize.define(
'companies',
{
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
name: {
type: DataTypes.STRING(50),
unique: true,
allowNull: false
},
image_url: {
type: DataTypes.STRING(100),
unique: true
},
created_at: {
allowNull: true,
type: DataTypes.DATE,
defaultValue: Date.now()
},
updated_at: {
allowNull: true,
type: DataTypes.DATE,
defaultValue: Date.now()
}
},
{
//Rewrite default behavior of sequelize
timestamps: false,
paranoid: true,
underscored: true
}
);
Companies.hasMany(Users);
Users.belongsTo(Companies);
Companies.sync();
module.exports = Companies;
models/users.js
const DataTypes = require('sequelize');
const sequelize = require('../config/database');
const Users = sequelize.define(
'users',
{
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
name: {
type: DataTypes.STRING(40),
allowNull: false
},
email: {
type: DataTypes.STRING(60),
allowNull: false,
unique: true
},
password: {
type: DataTypes.STRING(60)
},
role: {
type: DataTypes.STRING(40),
allowNull: false
},
image_url: {
type: DataTypes.STRING(100),
unique: true
},
batch: {
type: DataTypes.STRING(3)
},
major: {
type: DataTypes.STRING(10)
},
company_id: {
type: DataTypes.INTEGER,
allowNull: false
},
created_at: {
allowNull: true,
type: DataTypes.DATE,
defaultValue: Date.now()
},
updated_at: {
allowNull: true,
type: DataTypes.DATE,
defaultValue: Date.now()
}
},
{
//Rewrite default behavior of sequelize
timestamps: false,
paranoid: true,
underscored: true
}
);
Users.sync();
module.exports = Users;
Then after I try to run this code below
const Companies = require('./database/models/companies');
const Users = require('./database/models/Users');
//Relation 1: Company and Users
Companies.findAll({ include: [ Users ] }).then((res) => console.log(res));
Users.findAll({ include: [ Companies ] }).then((res) => console.log(res));
it gives me this error:
(node:4893) UnhandledPromiseRejectionWarning: SequelizeEagerLoadingError: companies is not associated to users!
I've tried a couple of solutions online but it didn't help in this case.
BelongsTo means one to one relationship while a company may have multiple users (meaning, calling BelongsTo after hasMany collide!).
For more: https://sequelize.org/master/manual/assocs.html

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 error : cannot find property "startYear" of undefined

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')
}
}
}

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