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.
Related
I have the following problem:
I defined my tables (product and collection) like this:
module.exports = (sequelize, type) => {
return sequelize.define('product', {
id: {
type: type.UUID,
primaryKey: true,
defaultValue: type.UUIDV4,
},
title: {
type: type.STRING,
allowNull: false,
},
description: {
type: type.TEXT,
allowNull: false,
},
width: {
type: type.FLOAT,
allowNull: false,
},
height: {
type: type.FLOAT,
allowNull: false,
},
weight: {
type: type.FLOAT,
allowNull: false,
},
length: {
type: type.FLOAT,
allowNull: false,
},
vendor: {
type: type.STRING,
allowNull: false,
},
status: {
type: type.ENUM,
values: ['inactive', 'active'],
defaultValue: 'active',
allowNull: false,
},
})
}
module.exports = (sequelize, type) => {
return sequelize.define('collection', {
id: {
type: type.UUID,
primaryKey: true,
defaultValue: type.UUIDV4,
},
name: {
type: type.STRING,
allowNull: false,
},
image: {
type: type.STRING,
allowNull: true,
},
createdAt: {
type: type.DATE,
allowNull: false,
},
updatedAt: {
type: type.DATE,
allowNull: false,
},
status: {
type: type.ENUM,
values: ['inactive', 'active'],
defaultValue: 'active',
allowNull: false,
},
})
}
Then, I need associated the tables (product and collection) with belongsToMany association and i did it like this:
const ProductModel = require('../api/product/model')
const CategoryModel = require('../api/category/model')
const Product = ProductModel(sequelize, Sequelize)
const Collection = CollectionModel(sequelize, Sequelize)
Product.belongsToMany(Collection, {
through: ProductCollection,
foreignKey: 'productId',
otherKey: 'collectionId',
unique: false,
})
Collection.belongsToMany(Product, {
through: ProductCollection,
foreignKey: 'collectionId',
otherKey: 'productId',
unique: false,
})
Now, i want to get all the products of a collection given by the id sent from the body of the request, i have little time working with sequelize and i donĀ“t know how to do this kind of query.
Can you help me with that?
you can use something like this
let products = Collection.findAll({
where: {
id: collection.id,
},
attributes: ['id', 'name'],
include: [{
model: Product,
through: {
model: ProductCollection,
},
as: 'products',
attributes: ['id', 'title', 'description']
}],
});
return products
hope it helps
i have these 2 models:
module.exports = function(sequelize, DataTypes) {
return sequelize.define('services_prices', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true
},
service_id: {
type: DataTypes.INTEGER(11),
allowNull: true,
references: {
model: 'services',
key: 'id'
}
},
created_at: {
type: DataTypes.DATE,
allowNull: false
},
limit: {
type: DataTypes.INTEGER(11),
allowNull: true
},
price: {
type: DataTypes.INTEGER(11),
allowNull: true
}
});
};
which is parent of this model: (services_user_prices can override services_prices )
module.exports = function(sequelize, DataTypes) {
return sequelize.define('services_user_prices', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
user_id: {
type: DataTypes.INTEGER(11),
allowNull: true
},
created_at: {
type: DataTypes.DATE,
allowNull: false
},
currency: {
type: DataTypes.STRING(255),
allowNull: true
},
is_active: {
type: DataTypes.INTEGER(1),
allowNull: true,
defaultValue: '0'
},
is_trial: {
type: DataTypes.INTEGER(1),
allowNull: true,
defaultValue: '0'
},
start_date: {
type: DataTypes.DATE,
allowNull: false
},
end_date: {
type: DataTypes.DATE,
allowNull: true
},
price: {
type: DataTypes.INTEGER(11),
allowNull: true
},
bundle_price_id: {
type: DataTypes.INTEGER(11),
allowNull: true,
references: {
model: 'services_prices',
key: 'id'
}
}
});
};
when trying to join them i get an error:
EagerLoadingError: services_prices is not associated to services_user_prices!
const result= await db.services_user_prices.findOne({
where: { is_active: 1, user_id: 123 }, include:[{db.services_prices}]
});
in the db services_user_prices has foreign key to services_prices table
what am i doing wrong?
Well if you are using sequelize then you need to update your model because
by default, sequelize will be looking for foreign key starts with model name like
you have defined bundle_price_id as a foreign key for services_prices.
You need to change your column name to services_price_id then it will get fixed.
or if you want to use bundle_price_id you need to define it in your model relation as.
Model.belongsTo(models.ModelName, { foreignKey: 'your_key'} )
Please feel free if you need to ask anything else.
As complement of the above answer you need to add an identifier with as: on the association like this:
Model.belongsTo(models.ModelName, { foreignKey: 'your_key', as:'your_identifier' } )
Then when you do the include on the method you also call the identifier:
await db.services_user_prices.findOne({
where: { is_active: 1, user_id: 123 },
include:[{
model: db.services_prices
as: 'your_identifier'
}]
});
If you don't define the foreignKey field, the as field will set the column name.
I'm trying to make this connection between these two tables, but I'm not getting it and it's giving the following error: "UnhandledPromiseRejectionWarning: SequelizeEagerLoadingError: cfg_user is not associated to dn_coluna!"
follows below the controllers and models that I am using to inner join
This is my cfg_user.js
const sequelizePaginate = require("sequelize-paginate");
module.exports = function(sequelize, DataTypes) {
const cfg_user = sequelize.define("cfg_user", {
'id_cfg_user': {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
'id_cfg_grupo': {
type: DataTypes.INTEGER(11),
allowNull: true
},
'nome': {
type: DataTypes.CHAR(100),
allowNull: true
},
'email': {
type: DataTypes.CHAR(100),
allowNull: true
},
'arquivo': {
type: DataTypes.CHAR(255),
allowNull: false
},
'senha': {
type: DataTypes.CHAR(32),
allowNull: true
}
},{
tableName: "cfg_user",
freezeTableName: true,
timestamps: false
});
sequelizePaginate.paginate(cfg_user);
return cfg_user;
};
This is my dn_coluna.js
const sequelizePaginate = require("sequelize-paginate");
const cfg_user = require("./cfg_user");
module.exports = function(sequelize, DataTypes) {
const dn_coluna = sequelize.define("dn_coluna", {
'id_dn_coluna': {
type: DataTypes.INTEGER(10),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
'id_cfg_user': {
type: DataTypes.INTEGER(10),
allowNull: false
},
'coluna': {
type: DataTypes.CHAR(255),
allowNull: false
},
'frase': {
type: DataTypes.CHAR(255),
allowNull: true,
},
'resumo': {
type: DataTypes.CHAR(255),
allowNull: true,
},
'url': {
type: DataTypes.CHAR(255),
allowNull: true
},
'arquivo': {
type: DataTypes.CHAR(255),
allowNull: true
},
'arquivo_topo': {
type: DataTypes.CHAR(255),
allowNull: true
},
'arquivo_bg': {
type: DataTypes.CHAR(255),
allowNull: true
},
'ordem': {
type: DataTypes.INTEGER(11),
allowNull: true
},
'destaque':{
type: DataTypes.TINYINT(1),
allowNull: true
},
'libera': {
type: DataTypes.TINYINT(1),
allowNull: true
}
},{
tableName: "dn_coluna",
freezeTableName: true,
timestamps: false
});
sequelizePaginate.paginate(dn_coluna);
return dn_coluna;
};
this is my Controller
const { dn_coluna } = require("../models");
const { cfg_user } = require("../models");
module.exports = {
async index(req, res){
const colunas = await dn_coluna.findAll({
include: [{
model: cfg_user,
attributes: []
}],
attributes: ['id_cfg_user'],
})
.then(colunas => {
return res.status(200).json(colunas);
});
},
};
Your answer lies in associations. You are not properly associating your tables together. Here is a link to the documentation. I am unsure of the type of relationship that cfg_user and dn_coluna have so I can't show you how to write the association but the below may help.
Remove the below from dn_coluna.js
'id_cfg_user': {
type: DataTypes.INTEGER(10),
allowNull: false
}
Add in to dn_coluna.js (just above sequelizePaginate.paginate(dn_coluna);):
dn_coluna.associate = (models) => {
dn_coluna.hasMany(models.cfg_user, {foreignKey: 'cfg_user_id'})
}
In cfg_user.js add (just above sequelizePaginate.paginate(cfg_user);):
cfg_user.associate = (models) => {
cfg_user.belongsTo(models.dn_coluna)
}
The above will create a one to many relationship between dn_coluna and cfg_user.
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')
}
}
}
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;
})
})