Sequelize association include returns null - javascript

I am having an issue when I'm trying to associate a table into my query with sequelize-cli.
My query works but it doesn't populate Adresse table. Only Patient is populated. Adresse array is ignored. (return null)
I made a one-to-one relationship between the tables and am not sure if that's the cause of the error or if it is somewhere else where I am associating the two tables.
here is my models :
server/models/patient.js
module.exports = (sequelize, Sequelize) => {
const Patient = sequelize.define('Patient', {
///
}, {
classMethods: {
associate: (models) => {
Patient.belongsTo(models.Adresse, {
foreignKey: 'adresseId',
});
}
}
});
return Patient;
};
server/models/adresse.js
module.exports = function(sequelize, Sequelize) {
const Adresse = sequelize.define('Adresse', {
adresse: {
type: Sequelize.STRING,
allowNull: false,
},
complementAdr: {
type: Sequelize.STRING
},
codePostal: {
type: Sequelize.INTEGER,
allowNull: false
},
}, {
classMethods: {
associate: (models) => {
Adresse.hasMany(models.Patient, {
foreignKey: 'adresseId',
as: 'Patients',
});
}
}
});
return Adresse;
};
and here is where I specified the association on my migration files :
server/migrations/20170326145609-create-patient.js
adresseId: {
type: Sequelize.INTEGER,
references: {
model: 'Adresses',
key: 'id_adresse',
as: 'adresseId',
},
},
server/migrations/20170326145502-create-adresse.js
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Adresses', {
id_adresse: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
adresse: {
type: Sequelize.STRING,
allowNull: false,
},
complementAdr: {
type: Sequelize.STRING
},
codePostal: {
type: Sequelize.INTEGER,
allowNull: false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: function(queryInterface, Sequelize) {
return queryInterface.dropTable('Adresses');
}
};
and finally here is my query on my controller file :
server/controllers/patients.js
const express = require('express');
const router = express.Router();
const jwt = require('jsonwebtoken');
const Patient = require('../models').Patient;
const Adresse = require('../models').Adresse;
module.exports = {
create(req, res) {
return Patient
.create({
///
adressesId: {
adresse: req.body.adresse,
codePostal: req.body.codePostal,
}
}, {
include: [{
model : Adresse
}]
})
.then(patient => res.status(201).send(patient))
.catch(error => res.status(400).send(error));
}
};

Try using Adresse instead adresseId when eager creating the Adresse model instance related to given Patient
return Patient.create({
// patient attributes,
Adresse: {
adresse: req.body.adresse,
codePostal: req.body.codePostal
},
include: [ Adresse ]
}).then(patient => {
// look at the query generated by this function
// it should create both patient and adresse
});

Related

Column specified twice error in sequelize

I have defined two table with many-to-many association between them.
create-image-migration.js
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Images', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING
},
...
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Images');
}
};
create-category-migration.js
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Categories', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING
},
...
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Categories');
}
};
Now JOIN table is defined as follows
create-image-category-migration.js
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('ImageCategories', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
imageId: {
type: Sequelize.INTEGER,
allowNull: false,
references: { model: 'Images', key: 'id' }
},
categoryId: {
type: Sequelize.INTEGER,
allowNull: false,
references: { model: 'Categories', key: 'id' }
},
...
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('ImageCategories');
}
};
image-category-model.js
'use strict';
module.exports = (sequelize, DataTypes) => {
const ImageCategory = sequelize.define('ImageCategory', {
imageId: {
type: DataTypes.INTEGER,
allowNull: false,
references: { model: 'Image', key: 'id' },
},
categoryId: {
type: DataTypes.INTEGER,
allowNull: false,
references: { model: 'Category', key: 'id' },
},
...
}, {});
ImageCategory.associate = function(models) {
models.Image.belongsToMany(models.Category, { through: ImageCategory });
models.Category.belongsToMany(models.Image, { through: ImageCategory });
};
return ImageCategory;
};
Now when I run the migration the join table is created with respective column name as specified in migration file i.e. in camel case.
But when I run the following bulkCreate command in sequelize to insert data
await db.ImageCategory.bulkCreate([
{ imageId: 'someId', categoryId: topicId, categoryType: 'topic' },
{ imageId: 'someId', categoryId: styleId, categoryType: 'style' },
]);
I am get the following error:
sqlMessage: "Column 'imageId' specified twice",
sql: "INSERT INTO `ImageCategories` (`imageId`,`categoryId`,`categoryType`,`createdAt`,`updatedAt`,`ImageId`) VALUES (5,'22','topic','2022-11-26 08:11:41','2022-11-26 08:11:41',NULL),(5,'27','style','2022-11-26 08:11:41','2022-11-26 08:11:41',NULL);"
},
As we can see here "ImageId" is automatically added by sequelize. So my question is if there is a convention followed by sequelize to name the column name while creating join table since it is not mention anywhere on its documentation.
By default Sequelize generates foreign key names in the pascal case. You do have foreign keys in the junction table that differ with the letter case.
So you just need to indicate foreign keys explicitly in both associations:
ImageCategory.associate = function(models) {
models.Image.belongsToMany(models.Category, { through: ImageCategory, foreignKey: 'imageId' });
models.Category.belongsToMany(models.Image, { through: ImageCategory, foreignKey: 'categoryId' });
};

Sequelize: A is not associated to B" nodejs

I have two models in which one is Question and other is Answer, each answer has one question_id and question can have more then one answers.
I want to include all the answers of each question in my json response but I am keep getting an error
"message": "answer is not associated to question!"*
Below is the Question model:-
module.exports = (sequelize, Sequelize) => {
const Question = sequelize.define("question", {
question_id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
question_no: {
type: Sequelize.DOUBLE,
allowNull: false
},
question_text: {
type: Sequelize.STRING,
allowNull: false
},
question_text: {
type: Sequelize.STRING,
allowNull: false
},
question_required: {
type: Sequelize.BOOLEAN,
},
formpage_no: {
type: Sequelize.DOUBLE,
allowNull: false
},
med_id: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'medforms',
key: 'med_id'
},
onUpdate: 'CASCADE',
onDelete: 'CASCADE'
},
med_name: {
type: Sequelize.STRING,
allowNull: true
},
version_no: {
type: Sequelize.STRING,
allowNull: false
}
}, {
freezeTableName: false, // true: if we want to make table name as we want else sequelize will make them prural
underscored: true // underscored: true indicates the the column names of the database tables are snake_case rather than camelCase
});
Question.associate = function (models) {
Question.hasMany(models.answer, {
foreignKey: 'question_id',
as: 'answers'
});
Question.hasMany(models.helpbox, {
foreignKey: 'question_id',
as: 'helpboxes'
});
// in future each question could have more than one document text
};
return Question;
};
And below is my answer model:-
module.exports = (sequelize, Sequelize) => {
const Answer = sequelize.define("answer", {
answer_id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
question_id: { // each answer has one questionId
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'questions',
key: 'question_id'
},
onUpdate: 'CASCADE',
onDelete: 'CASCADE',
},
question_no: {
type: Sequelize.DOUBLE,
allowNull: true
},
answer_no: {
type: Sequelize.DOUBLE,
allowNull: true
},
answer_text: {
type: Sequelize.STRING,
allowNull: false
},
answer_icon: {
type: Sequelize.STRING,
allowNull: true
},
answer_reply: {
type: Sequelize.STRING,
allowNull: true
},
answer_logic: {
type: Sequelize.STRING,
allowNull: true
},
med_name: {
type: Sequelize.STRING,
allowNull: true
},
version_no: {
type: Sequelize.STRING,
allowNull: false
},
}, {
freezeTableName: false, // true: if we want to make table name as we want else sequelize will make them prural
underscored: true // underscored: true indicates the the column names of the database tables are snake_case rather than camelCase
});
Answer.associate = function (models) {
Answer.belongsTo(models.question, {
as: 'questions'
});
// in future each question could have more than one document text
};
return Answer;
};
below is the index.js class:-
var Sequelize = require('sequelize');
var env = process.env.NODE_ENV || 'development';
var config = require("../config/config.json")[env];
var db = {};
if (config.use_env_variable) {
var sequelize = new Sequelize(process.env[config.use_env_variable]);
} else {
var sequelize = new Sequelize(config.database, config.username, config.password, config);
}
db.Sequelize = Sequelize;
db.sequelize = sequelize;
// Models
db.medform = require("./medform.model.js")(sequelize, Sequelize);
db.version = require("./version.model.js")(sequelize, Sequelize);
db.question = require("./question.model.js")(sequelize, Sequelize);
db.helpbox = require("./helpbox.model.js")(sequelize, Sequelize);
db.answer = require("./answer.model.js")(sequelize, Sequelize);
db.document = require("./document.model.js")(sequelize, Sequelize);
module.exports = db;
This is my question controller
// Retrieve Question including answers from the database:
exports.getAllQuesData = (req, res) => {
const version_no = req.query.version_no;
const med_id = req.query.med_id;
var condition = [{ "version_no": version_no }, { "med_id": med_id }];
Question.findAll({
include: [
{
model: answer,
as: 'answers'
}
],
where: condition
})
.then(data => {
res.send(data);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Some error occurred while retrieving questions."
});
});
};
Please help me what I am doing wrong why my associations are not working
You didn't register model associations. See my answer how to do it
Object.keys(db).forEach(function (modelName) {
if (db[modelName].associate) {
db[modelName].associate(db)
}
})

how to use transactions in sequelize?

I have written two classes and migrations files for MySQL database using sequelize.
how can I save the user and his children using transactions in node.js? I want to create, a class where I can encapsulate all the database communications in one file and then call it from my CRUD methods.
user class :
'use strict';
module.exports = function(sequelize, DataTypes) {
const User = sequelize.define('User', {
id : {
type: DataTypes.INTEGER(11),
allowNull: false,
autoIncrement:true,
primaryKey:true
},
firstName : {
type: DataTypes.STRING(50),
allowNull: false
},
lastName : {
type: DataTypes.STRING(50),
allowNull: false
},
dateOfBirth : {
type: DataTypes.DATE,
allowNull: false
}
});
return User;
};
children class :
'use strict';
module.exports = function(sequelize, DataTypes) {
const Children= sequelize.define('Children', {
id : {
type: DataTypes.INTEGER(11),
allowNull: false,
autoIncrement:true,
primaryKey:true
},
userId : {
type: DataTypes.INTEGER(11),
allowNull: true,
references : {
model : 'Users',
key:'id'
}
},
status : {
type: DataTypes.BOOLEAN,
allowNull: false,
defaulValue: false
},
firstName : {
type: DataTypes.STRING(50),
allowNull: false
},
lastName : {
type: DataTypes.STRING(50),
allowNull: false
},
dateOfBirth : {
type: DataTypes.DATE,
allowNull: false
}
});
return Children;
};
Try :
let transaction;
try {
// get transaction
transaction = await sequelize.transaction();
//save here
User.build({
firstName: "John"
//other attributes
}).save().then(newUser => {
const id = newUser.id;
Children.build({
firstNames: "fsf"
userId: id // from newly created user
//other attributes
})
.save()
.then(children => console.log("svaed"))
}).catch(function(error) {
// error
});
// commit
await transaction.commit();
} catch (err) {
// Rollback transaction
if (transaction) await transaction.rollback();
}

Associate in Sequelize not working as intended

I am trying to associate two tables in Sequelize but I am getting the SequelizeEagerLoadingError that one table is not associated to another despite trying all the available fixes on this platform.
I have two tables, User and Item.
User (user.js)
const User = dbconnection.sequelize.define('users', {
id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true},
name: {
type: Sequelize.STRING(80),
allowNull: false
},
email: {
type: Sequelize.STRING(120),
allowNull: false,
unique: true
},
dob: {
type: Sequelize.DATEONLY,
allowNull: false
},
password: {
type: Sequelize.STRING(256),
allowNull: false
}
});
User.associate = models => {
User.hasMany(models.Item, { as: 'items',foreignKey: 'user_id' })
}
dbconnection.sequelize.sync({ force: false })
.then(() => {
//console.log('Table created!')
});
module.exports = {
User
};
Item (item.js)
const Item = dbconnection.sequelize.define('items', {
id: { type: Sequelize.INTEGER, unique: true, autoIncrement: true, primaryKey: true},
item: {
type: Sequelize.STRING(80),
allowNull: true
},
item_type: {
type: Sequelize.STRING(10),
allowNull: false
},
comment: {
type: Sequelize.STRING(1000),
allowNull: true
},
user_id: {
type: Sequelize.INTEGER,
allowNull: false,
references: { model: 'users', key: 'id' }
},
});
Item.associate = models => {
Item.belongsTo(models.User, { as: 'users',foreignKey: 'user_id' })
}
dbconnection.sequelize.sync({ force: false })
.then(() => {
// console.log('Table created!')
})
});
module.exports = {
Item
};
User hasMany(Item) while Item belongsTo(User) as shown above.
However, when I make a query to the Item table (as below),
const usersdb = require('./userdb')
const itemsdb = require('./itemdb')
class ItemsController {
static async getAllItems(req, res, next) {
try{
let allitems = await itemsdb.Item.findAll({
include: [{
model: usersdb.User
}]
})
return {items: allitems, status: true}
}
catch (e) {
return {items: e, status: false}
}
}
}
module.exports = ItemsController;
I get the SequelizeEagerLoadingError that "users is not associated to items!"
I have tried all the available fixes including this and this among others but to no success.
I have finally found a workaround. First, I dropped the tables and discarded the model definitions. Second, I generated migrations and models using the sequelize model:create --name ModelName --attributes columnName:columnType command. I then used the generated models to associate the two tables just as I had done earlier. Lastly, I ran the sequelize db:migrate command to create the tables and on running the query, it worked!
Earlier, I was creating the models manually. I was also creating the tables using the sequelize.sync({force: false/true}) command after loading the models.
User Model (user.js)
'use strict';
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
email: {
type: DataTypes(120),
allowNull: false,
unique: true
},
dob: {
type: DataTypes.DATEONLY,
allowNull: false
},
password: {
type: DataTypes.STRING(256),
allowNull: false
}
}, {});
User.associate = function(models) {
User.hasMany(models.Item, {as: 'Item', foreignKey: 'user_id'})
};
return User;
};
Item model (item.js)
'use strict';
module.exports = (sequelize, DataTypes) => {
const Item = sequelize.define('Item', {
item: {
type: DataTypes.STRING(80),
allowNull: true
},
item_type: {
type: DataTypes.STRING(10),
allowNull: false
},
comment: {
type: DataTypes.STRING(1000),
allowNull: true
},
user_id: {
type: DataTypes.INTEGER,
allowNull: false,
references: { model: 'User', key: 'id' }
}
}, {});
Item.associate = function(models) {
Item.belongsTo(models.User, { as: 'User',foreignKey: 'user_id' })
};
return Item;
};
Query (queryitem.js)
const Item = require('../models').Item
const User = require('../models').User
class ItemsController {
static async getAllItems() {
try{
let allitems = await Item.findAll({
include: [{
model: User,
as: 'User'
}]
})
return {items: allitems, status: true}
}
catch (e) {
return {items: e, status: false}
}
}
}
module.exports = ItemsController;

Sequelize join data in tree

I have 3 models that work like a tree: Plants, Genre and family.
Each family can have a lot of genres each genre is associated to 1 family.
Same for Genre, each 1 can have a lot of plants and 1 plant can have 1 genre.
So based on that, i have this models:
Plant
"use strict";
var sequelize = require('./index');
var bcrypt = require('bcrypt-nodejs');
var User = require('./User');
module.exports = function (sequelize, DataTypes) {
var Plant = sequelize.define("Plant", {
specie: {
type: DataTypes.STRING,
allowNull: false,
},
description: {
type: DataTypes.TEXT,
allowNull: true,
defaultValue: "No description for this plant yet"
},
directory: {
type: DataTypes.STRING,
allowNull: false
},
genreId: {
type: DataTypes.INTEGER,
allowNull: true
}
},
{
associate: function (models) {
Plant.hasMany(models.Foto, { foreignKey: "plantId", as: 'fotos' });
}
}
);
Genre
module.exports = function (sequelize, DataTypes) {
var Genre = sequelize.define("Genre", {
name: {
type: DataTypes.STRING,
allowNull: false
},
familyId: {
type: DataTypes.INTEGER,
allowNull: true
},
directory: {
type: DataTypes.STRING,
allowNull: false
}
},
{
associate: function (models) {
Genre.hasMany(models.Plant, { foreignKey: "genreId", as: 'plant' });
}
}
);
Family
module.exports = function (sequelize, DataTypes) {
var Family = sequelize.define("Family", {
name: {
type: DataTypes.STRING,
allowNull: false
},
directory: {
type: DataTypes.STRING,
allowNull: false
}
},
{
associate: function (models) {
Family.hasMany(models.Genre, { foreignKey: "familyId", as: 'genre' });
}
}
);
now, i do a query where i want to get all data related to the plant(genre and family) so i pass the id for the plant in the routing, via req.params.id.
after that i try to do a include so i can get the data with eager loading, because i need to get a json with all the data related to the plant.
But i can't get any data related to the other models, just with the specific plant table, any help?
Here is the controller code on the server:
specificPlant: function (req, res, next) {
Plant.findAll({
where: {
id: req.params.id,
},
include: [{ all: true }]
}).then(function (plant) {
console.log(plant);
return res.send(plant);
}).catch(function (err) {
return res.status(400).send({ message: err.stack }); //
})
}
First, define associations that will allow you to get data Plant->Genre->Family
Plant.hasMany(models.Genre, {foreignKey: "genreId", as: 'genre' });
Genre.hasMany(models.Family, { foreignKey: "familyId", as: 'family' });
Then you can query
Plant.findAll({
where: {
id: req.params.id,
},
include: [{
model: Genre,
as: 'genre',
include: [{
model: Family,
as: 'family'
}]
}]
}).then(function (plant) {
//plant
//plant.genre
//plant.genre.family
});

Categories