Sequelize.js - "is not associated to" - javascript

I have some issue with getting full data from db.
That are my models:
User
module.exports = function(sequelize, DataTypes) {
return sequelize.define('user', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true,
field: 'ID'
},
password: {
type: DataTypes.STRING(255),
allowNull: false,
field: 'password'
},
email: {
type: DataTypes.STRING(255),
allowNull: false,
unique: true,
field: 'email'
},
roleId: {
type: DataTypes.INTEGER(11),
allowNull: false,
references: {
model: 'role',
key: 'ID'
},
field: 'role_id'
}
}, {
timestamps: false,
tableName: 'user'
});
};
Role
module.exports = function(sequelize, DataTypes) {
return sequelize.define('role', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true,
field: 'ID'
},
name: {
type: DataTypes.STRING(255),
allowNull: false,
unique: true,
field: 'name'
},
description: {
type: DataTypes.STRING(255),
allowNull: false,
field: 'description'
},
permission: {
type: DataTypes.INTEGER(11),
allowNull: false,
field: 'permission'
}
}, {
timestamps: false,
tableName: 'role',
});};
I want to get object of one specific user including all role content.
Somethink like
{
id: 4,
password: 'xxx',
email: 'adsads#saas.com',
role: {
id: 2,
name: 'admin'
description: 'ipsum ssaffa',
permission: 30
}
}
So I'm using:
User.findOne( { where: { id: req.userId }, include: [ Role ] } ).then( user =>{...});
but I get in the result err.message: "role is not associated to user"
And the simple question - what's wrong ? :)
*to handle models I'm using sequelize-cli

You get this error because you didn't add associate between the models
base on your json I see that each user only has one role, so you can either use belongsTo in role model or hasOne in user model
Should be something like this:
User.js
module.exports = function(sequelize, DataTypes) {
var user = sequelize.define('user', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true,
field: 'ID'
},
password: {
type: DataTypes.STRING(255),
allowNull: false,
field: 'password'
},
email: {
type: DataTypes.STRING(255),
allowNull: false,
unique: true,
field: 'email'
},
roleId: {
type: DataTypes.INTEGER(11),
allowNull: false,
references: {
model: 'role',
key: 'ID'
},
field: 'role_id'
}
}, {
timestamps: false,
tableName: 'user'
});
user.associate = function(models) {
user.hasOne(models.role, {foreignKey: 'id',sourceKey: 'roleId'});
}
return user;
};
Role.js
module.exports = function(sequelize, DataTypes) {
var role = sequelize.define('role', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true,
field: 'ID'
},
name: {
type: DataTypes.STRING(255),
allowNull: false,
unique: true,
field: 'name'
},
description: {
type: DataTypes.STRING(255),
allowNull: false,
field: 'description'
},
permission: {
type: DataTypes.INTEGER(11),
allowNull: false,
field: 'permission'
}
}, {
timestamps: false,
tableName: 'role',
});
role.associate = function(models) {
user.belongsTo(models.role, {foreignKey: 'id'});
}
return role;
};

You have to declare associations between your Models. If using Sequelize CLI make sure the static method associate is being called. Example:
/models.index.js
const Category = require('./Category');
const Product = require('./Product');
const ProductTag = require('./ProductTag');
const Tag = require('./Tag');
Category.associate({Product});
Product.associate({Category,Tag});
Tag.associate({Product});
module.exports={Category,Product,ProductTag,Tag};
and then the association in Category.js
'use strict';
const {Model,DataTypes} = require('sequelize');
const sequelize = require('../config/connection.js');
class Category extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method.
*/
static associate({Product}) {
// define association here
console.log('Category associated with: Product');
this.hasMany(Product, {
foreignKey: 'category_id',
onDelete: 'CASCADE'
});
}
}
Category.init({
category_id: {type: DataTypes.INTEGER, autoIncrement: true, allowNull: false, primaryKey: true},
category_name: {type: DataTypes.STRING, allowNull: false}
}, {
sequelize,
timestamps: false,
freezeTableName: true,
underscored: true,
modelName: "Category",
});
module.exports = Category;

Related

Sqlite Foreign key mismatch sequelize migration

My request SQL fail when I try to insert data in my table PostVotes
I use sequelize migration to migrate my database and I have the same probleme when I make my sql request in my console.
sequelize db:migrate
When I use sequelize.sync() i don't have this problem
My table:
/* TABLE Users */
queryInterface.createTable('Users', {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
},
password: {
type: Sequelize.STRING,
allowNull: false,
},
email: {
type: Sequelize.STRING,
allowNull: false,
unique: true,
},
}),
queryInterface.createTable('Posts', {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
},
title: {
type: Sequelize.STRING,
allowNull: false,
},
userId: {
type: Sequelize.UUID,
primaryKey: true,
onDelete: 'CASCADE',
references: {
model: 'Users',
key: 'id',
},
},
}),
/* Table posts votes*/
queryInterface.createTable('PostVotes', {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
},
vote: {
// eslint-disable-next-line new-cap
type: Sequelize.ENUM('up', 'down'),
validate: {
isIn: [['up', 'down']],
},
allowNull: false,
},
userId: {
type: Sequelize.UUID,
primaryKey: true,
onDelete: 'CASCADE',
references: {
model: 'Users',
key: 'id',
},
},
postId: {
type: Sequelize.UUID,
primaryKey: true,
onDelete: 'CASCADE',
references: {
model: 'Posts',
key: 'id',
},
},
}),
[Error: SQLITE_ERROR: foreign key mismatch - "PostVotes" referencing "Posts"]
I already find answer but nothing is working. I think my mistake is in the table PostVotes but I don't understand what.
Thanks !
FIX
queryInterface.createTable('Posts', {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
},
title: {
type: Sequelize.STRING,
allowNull: false,
},
userId: {
type: Sequelize.UUID,
primaryKey: true, # DELETE THIS ONE
onDelete: 'CASCADE',
references: {
model: 'Users',
key: 'id',
},
},
}),
I delete primaryKey in table Post column userId

Sequelise : Many To Many table(CROSS TABLE) associated to other table

This is my Diagram DATABASE : https://i.stack.imgur.com/CGAwh.png
I made models of my databases with SEQUELIZE like that :
MODEL : Level
module.exports = (sequelize, DataTypes) => {
const Level = sequelize.define(
'Level',
{
level_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
label: {
type: DataTypes.STRING,
allowNull: false,
unique: {
args: true,
msg: 'Level:Label already exist!',
},
validate: {
notEmpty: { msg: `Level:Label cannot be empty!` },
notNull: { msg: `Level:Label cannot be NULL!` },
},
},
ref: {
type: DataTypes.STRING,
allowNull: true,
},
description: {
type: DataTypes.TEXT,
allowNull: true,
},
},
{
tableName: 'levels',
timestamps: false,
}
);
Level.associate = (models) => {
Level.belongsToMany(models.Test, {
through: models.testHasLevel,
foreignKey: 'level_id',
otherKey: 'test_id',
timestamps: false,
});
};
return Level;
};
Model : TEST :
module.exports = (sequelize, DataTypes) => {
const Test = sequelize.define(
'Test',
{
test_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
label: {
type: DataTypes.STRING,
allowNull: false,
validate: {
notEmpty: { msg: `Test:label cannot be empty!` },
notNull: { msg: `Test:label cannot be NULL!` },
},
},
isInternal: {
type: DataTypes.BOOLEAN,
defaultValue: false,
allowNull: false,
validate: {
notEmpty: { msg: `Test:isInternal cannot be empty!` },
notNull: { msg: `Test:isInternal cannot be NULL!` },
},
},
parent_id: {
type: DataTypes.INTEGER,
defaultValue: null,
allowNull: true,
},
},
{
tableName: 'tests',
timestamps: false,
}
);
Test.associate = (models) => {
Test.belongsToMany(models.Level, {
through: models.testHasLevel,
foreignKey: 'test_id',
otherKey: 'level_id',
timestamps: false,
});
Test.hasMany(models.Test, { foreignKey: 'parent_id', as: 'children' });
};
return Test;
};
MODEL : TEST HAS MODEL
module.exports = (sequelize, DataTypes) => {
const testHasLevel = sequelize.define(
'testHasLevel',
{},
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
tableName: 'test_has_level',
timestamps: false,
}
);
testHasLevel.associate = (models) => {
testHasLevel.belongsTo(models.Test, {
foreignKey: 'test_id',
targetKey: 'test_id',
});
testHasLevel.belongsTo(models.Level, {
foreignKey: 'level_id',
targetKey: 'level_id',
});
};
return testHasLevel;
};
I made also SESSION MODEL :
module.exports = (sequelize, DataTypes) => {
const Session = sequelize.define(
'Session',
{
session_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
institut_id: {
type: DataTypes.INTEGER,
},
start: {
type: DataTypes.DATE,
},
end: {
type: DataTypes.DATE,
},
test_id: {
type: DataTypes.INTEGER,
},
level_id: {
type: DataTypes.INTEGER,
},
limitDateSubscribe: {
type: DataTypes.DATE,
},
placeAvailable: {
type: DataTypes.INTEGER,
},
},
{
tableName: 'sessions',
timestamps: false,
}
);
Session.associate = (models) => {
Session.hasMany(models.sessionHasUser, { foreignKey: 'session_id' });
};
return Session;
};
But i have no idea how to "BIND" SESSION with TEST_HAS_LEVEL with Sequelize ....
What should i change ? cause i know "composite key" are not allowed with the last version of sequelize.
In other term :
How associate properly a cross table with a one to many relationship to an other table ?
Model: Level
module.exports = (sequelize, DataTypes) => {
const Level = sequelize.define(
"Level",
{
level_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
label: {
type: DataTypes.STRING,
allowNull: false,
unique: {
args: true,
msg: "Level:Label already exist!",
},
validate: {
notEmpty: { msg: `Level:Label cannot be empty!` },
notNull: { msg: `Level:Label cannot be NULL!` },
},
},
ref: {
type: DataTypes.STRING,
allowNull: true,
},
description: {
type: DataTypes.TEXT,
allowNull: true,
},
},
{
tableName: "levels",
timestamps: false,
}
);
Level.associate = (models) => {
Level.hasMany(models.testHasLevel, {
foreignKey: "level_level_id",
as: "levels",
});
};
return Level;
};
Model: Test
module.exports = (sequelize, DataTypes) => {
const Test = sequelize.define(
"Test",
{
test_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
label: {
type: DataTypes.STRING,
allowNull: false,
validate: {
notEmpty: { msg: `Test:label cannot be empty!` },
notNull: { msg: `Test:label cannot be NULL!` },
},
},
isInternal: {
type: DataTypes.BOOLEAN,
defaultValue: false,
allowNull: false,
validate: {
notEmpty: { msg: `Test:isInternal cannot be empty!` },
notNull: { msg: `Test:isInternal cannot be NULL!` },
},
},
parent_id: {
type: DataTypes.INTEGER,
defaultValue: null,
allowNull: true,
},
},
{
tableName: "tests",
timestamps: false,
}
);
Test.associate = (models) => {
Test.hasMany(models.testHasLevel, {
foreignKey: "test_test_id",
as: "tests",
});
Test.hasMany(models.Test, { foreignKey: "parent_id", as: "children" });
};
return Test;
};
Model: Test has level
module.exports = (sequelize, DataTypes) => {
const testHasLevel = sequelize.define(
"testHasLevel",
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
test_test_id: {
type: DataTypes.INTEGER,
},
level_level_id: {
type: DataTypes.INTEGER,
},
},
{
tableName: "test_has_level",
timestamps: false,
}
);
testHasLevel.associate = (models) => {
testHasLevel.belongsTo(models.Test, {
foreignKey: "test_test_id",
as: "tests",
});
testHasLevel.belongsTo(models.Level, {
foreignKey: "level_level_id",
as: "levels",
});
testHasLevel.hasMany(models.Session, {
foreignKey: "test_has_level_id",
as: "test_has_level",
});
};
return testHasLevel;
};
Model: Session
module.exports = (sequelize, DataTypes) => {
const Session = sequelize.define(
"Session",
{
session_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
institut_id: {
type: DataTypes.INTEGER,
},
start: {
type: DataTypes.DATE,
},
end: {
type: DataTypes.DATE,
},
test_has_level_id: {
type: DataTypes.INTEGER,
},
limitDateSubscribe: {
type: DataTypes.DATE,
},
placeAvailable: {
type: DataTypes.INTEGER,
},
},
{
tableName: "sessions",
timestamps: false,
}
);
Session.associate = (models) => {
Session.belongsTo(models.testHasLevel, {
foreignKey: "test_has_level_id",
as: "test_has_level",
});
};
return Session;
};

How to use sequelize beforeCreate to autogenerate Id value?

I am tryiong to generate a BINARY(16) value for a model that Id.
I used the defaultValue parameter but ended up getting
duplicate key errors in mysql
.
So i found If I use beforeCreate then it would be uniqe every time but when Im doing the actual create im getting
Id can not be null errors
my model:
const utility = require('utils/utilities');
module.exports = function(sequelize, DataTypes) {
const weddings = sequelize.define(
'weddings', {
Id: {
primaryKey: true,
allowNull: false,
type: 'BINARY(16)',
},
Name: {
type: DataTypes.STRING(150),
allowNull: false,
comment: 'null',
},
HouseId: {
type: DataTypes.INTEGER(11),
allowNull: false,
comment: 'null',
references: {
model: 'house',
key: 'Id',
},
},
WDate: {
type: DataTypes.DATE,
allowNull: false,
comment: 'null',
},
Active: {
type: DataTypes.BOOLEAN,
allowNull: false,
comment: 'null',
},
},
{
hooks: {
beforeCreate() {
const generateValue = Buffer.from(utility.generateUID().replace('-', ''), 'hex');
weddings.Id = generateValue;
}
}
}, {
tableName: 'weddings',
}
);
return weddings;
};
error:
weddings.Id cannot be null
What am I missing?
You can use instance hook like this:
const utility = require('utils/utilities');
module.exports = function(sequelize, DataTypes) {
const weddings = sequelize.define(
'weddings', {
Id: {
primaryKey: true,
allowNull: false,
type: 'BINARY(16)',
},
Name: {
type: DataTypes.STRING(150),
allowNull: false,
comment: 'null',
},
HouseId: {
type: DataTypes.INTEGER(11),
allowNull: false,
comment: 'null',
references: {
model: 'house',
key: 'Id',
},
},
WDate: {
type: DataTypes.DATE,
allowNull: false,
comment: 'null',
},
Active: {
type: DataTypes.BOOLEAN,
allowNull: false,
comment: 'null',
},
},
{
}, {
tableName: 'weddings',
}
);
weddings.beforeCreate(async (data, options) => {
data.Id = await Buffer.from(utility.generateUID().replace('-', ''), 'hex');
});
return weddings;
};
If you want to emit hooks for each individual record, along with the bulk hooks you can pass individualHooks: true to the call.
table.update( req.body, {
where: where,
returning: true,
individualHooks: true
plain: true
})
create:
db.weddings.create({
...args,
}),
for other information you can read it at:
https://sequelize.org/v5/manual/hooks.html

Sequelize request error SequelizeEagerLoadingError

I’m new with sequelize I’m trying to make a request with associate tables
I have a first model called Experience
module.exports = function (sequelize, DataTypes) {
const Experience = sequelize.define('experience', {
internalId: {
type: DataTypes.BIGINT,
unique: true,
allowNull: false,
},
label: {
type: DataTypes.STRING,
unique: false,
allowNull: false,
},
picture: {
type: DataTypes.TEXT,
unique: false,
allowNull: true,
},
type: {
type: DataTypes.STRING,
validate: {
isIn: {
args: [[
'generic',
'specific',
]],
msg: 'Must be a valid type',
},
},
unique: false,
allowNull: true,
},
author: {
type: DataTypes.STRING,
unique: false,
allowNull: true,
defaultValue: 'import',
},
isActive: {
type: DataTypes.BOOLEAN,
defaultValue: true,
},
});
Experience.associate = (models) => {
Experience.belongsToMany(models.Tag, {
as: 'Tags',
through: models.ExperienceTag,
});
};
return Experience;
};
a second called Tags
module.exports = function (sequelize, DataTypes) {
const Tag = sequelize.define('tag', {
internalId: {
type: DataTypes.STRING,
unique: true,
allowNull: false,
},
name: {
type: DataTypes.STRING,
unique: false,
allowNull: false,
},
author: {
type: DataTypes.STRING,
unique: false,
allowNull: true,
defaultValue: 'import',
},
isActive: {
type: DataTypes.BOOLEAN,
defaultValue: true,
},
});
Tag.associate = (models) => {
Tag.belongsToMany(models.Experience, {
as: 'Experiences',
through: models.ExperienceTag,
});
};
return Tag;
};
The association table name was ExperienceTags
I would like get all the Experiencewho have a tagId = 44
This is my request:
Experience.findAll({
include: [{
model: ExperienceTag,
where: { tagId: 44 },
}],
})
.then((results) => {
winston.warn(JSON.stringify(results, null, 2));
res.status(200)
.send(results);
})
.catch(error => res.status(500)
.send({ error: error.toString() }));
But when I execute it I have an error like:
{
"error": "SequelizeEagerLoadingError: experienceTag is not associated to experience!"
}
I think you like to include Tag rather than ExperienceTag, the following example may help you
Experience.findAll({
include: [{
model: Tag, //model name which you want to include
as: 'Tags', // you have to pass alias as you used while defining
where: { tagId: 44 },
}],
})
I think , you need to add as: 'Experiences' , in your include as you have defined association with alias
Change this
Experience.findAll({
include: [{
model: ExperienceTag,
where: { tagId: 44 },
}],
})
With
Experience.findAll({
include: [{
model: ExperienceTag,
as: 'Experiences', // <---- HERE
where: { tagId: 44 },
}],
})

Returning parent attributes via sequelize

I am working on a NodeJs application using sequelize as an ORM with exciting database , so I had to use sequelize model generator in order to generate the models for my application.
Here's an example of the generation output:
Category.js
module.exports = function(sequelize, DataTypes) {
return sequelize.define('category', {
id: {
type: DataTypes.STRING(128),
allowNull: false,
primaryKey: true,
field: 'id'
},
name: {
type: DataTypes.TEXT,
allowNull: true,
field: 'name'
}
}, {
tableName: 'category'
});
};
Product.js
module.exports = function(sequelize, DataTypes) {
return sequelize.define('product', {
id: {
type: DataTypes.STRING(128),
allowNull: false,
primaryKey: true,
field: 'id'
},
category: {
type: DataTypes.STRING(128),
allowNull: false,
references: {
model: 'category',
key: 'id'
},
field: 'category'
},
name: {
type: DataTypes.TEXT,
allowNull: true,
field: 'name'
}
}, {
tableName: 'product'
});
};
and then inside my controller I have this query :
models.product.findOne({
where: {
id: req.body.id
}
}).then(function (obj) {
//return the product data
console.log(product.category) //works
console.log(product.category.name) //return undefined
});
The question is how can I access to the parent table attribute via the same query findOne ? Is there something like or equivalent to product.category.id ?
if you have associated both the models... then try this
module.exports = function(sequelize, DataTypes) {
return sequelize.define('product', {
id: {
type: DataTypes.STRING(128),
allowNull: false,
primaryKey: true,
field: 'id'
},
category_id: {
type: DataTypes.STRING(128),
allowNull: false,
references: {
model: 'category',
key: 'id'
},
field: 'category'
},
name: {
type: DataTypes.TEXT,
allowNull: true,
field: 'name'
}
}, {
tableName: 'product'
});
}
models.product.findOne({
where: {
id: req.body.id
},
include: [{
model: category,
required: false
}]
}).then(function (obj) {
//return the product data
console.log(product.category) //works
console.log(product.category.name) //return undefined
});
Associate like this
product.hasMany(db.category, {
foreignKey: 'category_id',
onDelete: 'cascade'
});
category.belongsTo(db.product, {
foreignKey: 'category_id',
targetKey: 'id',
constraints: true
});

Categories