Sequelize - called with something that's not a subclass of Sequelize.Model - node.js

I'm working on app but I having this issue using Node.js and Sequelize for Postgresql :
throw new Error(this.name + '.' + Utils.lowercaseFirst(Type.toString()) + ' called with something that\'s not a subclass of Sequelize.Model');
^
Error: Expense.class BelongsTo extends Association {
constructor(source, target, options) {
super(source, target, options);
<....LOT OF CODE FROM SEQUELIZE ....>
if ((fieldsOrOptions || {}).transaction instanceof Transaction) {
options.transaction = fieldsOrOptions.transaction;
}
options.logging = (fieldsOrOptions || {}).logging;
return association.target.create(values, fieldsOrOptions).then(newAssociatedObject =>
sourceInstance[association.accessors.set](newAssociatedObject, options)
);
}
} called with something that's not a subclass of Sequelize.Model
I don't understand this error, especially the last line "called with something that's not a subclass of Sequelize.Model".
Here is the models :
User model
const models = require('./index');
const Expense = models.User;
module.exports = (sequelize, DataTypes) => {
var User = sequelize.define('User', {
firstname: DataTypes.STRING,
lastname: DataTypes.STRING,
email: DataTypes.STRING,
password: DataTypes.STRING
}, {
classMethods: {
associate: function(models) {
User.hasMany(models.Expense);
}
}
});
console.log(models);
User.hasMany(Expense, {as: 'Expenses', foreignKey: 'userId'});
return User;
};
And Expense model
const models = require('./index');
const User = models.User;
module.exports = (sequelize, DataTypes) => {
var Expense = sequelize.define('Expense', {
name: DataTypes.STRING,
amount: DataTypes.INTEGER,
date: DataTypes.INTEGER
}, {
classMethods: {
}
});
Expense.belongsTo(User, { foreignKey: 'userId' });
return Expense;
};
And the controller for creating an expense :
createExpense: function(req, res) {
const user = User.findOne({ where: { id: req.params.id } });
Expense.create({
name: req.body.name,
amount: req.body.amount,
date: req.body.date,
User: user
},{
include: [
{
model: User
}
]
}).then((created) => {
res.status(200).send({ success: true, message: 'Dépense ajoutée !' });
});
}
Does someone have already see an error that look like that ? I search for few days without any issue, if someone could help I'll really appreciate,
thank !

I have a same problem before, but I found a reason. Key point is that your models must under a same sequelize class.
You can look my project mini-shop on github.

Though being 3 years late... I think, it's caused by a bad import. The import in in "User Model" for the "Expense Model" uses this line and looks kind of fishy:
const Expense = models.User;
But from a rather general point of view, this kind of error message might be a hint to an error while creating an association in a line such as User.hasMany(Expense, {as: 'Expenses', foreignKey: 'userId'});
Here is another answer regarding a similar question. For example in my case, the error came from not using the definition name to access my model (<- depends on your setup!)

Related

Node JS Sequelize many-to-many relationship throwing error column id does not exist

I am building a Node JS web application. I am using Sequelize, https://sequelize.org/ for manipulating the database logic. Now, I am having a problem with bulk insert and many-to-many relationships.
I have a model called, Region with the following code.
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Region extends Model {
static associate(models) {
// define association here
Region.belongsToMany(models.ExchangeRequest, {
through: 'RegionExchangeRequests',
as: 'exchangeRequests',
foreignKey: "region_id",
otherKey: "exchange_request_id"
})
}
};
Region.init({
name: DataTypes.STRING,
latitude: DataTypes.FLOAT,
longitude: DataTypes.FLOAT
}, {
sequelize,
modelName: 'Region',
});
return Region;
};
Then, I have a model called, ExchangeRequest with the following code.
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class ExchangeRequest extends Model {
static associate(models) {
// define association here
ExchangeRequest.belongsToMany(models.Region, {
through: 'RegionExchangeRequests',
as: 'regions',
foreignKey: 'exchange_request_id',
otherKey: "region_id"
})
ExchangeRequest.belongsTo(models.User, { foreignKey: 'userId', as: 'user', onDelete: 'cascade' });
}
};
ExchangeRequest.init({
exchange_rate: DataTypes.DECIMAL,
currency: DataTypes.STRING,
amount: DataTypes.DECIMAL,
buy_or_sell: DataTypes.INTEGER,
note: DataTypes.STRING,
email: DataTypes.STRING,
phone: DataTypes.STRING,
address: DataTypes.STRING,
userId: DataTypes.INTEGER
}, {
sequelize,
modelName: 'ExchangeRequest',
});
return ExchangeRequest;
};
Then I have the RegionExchangeRequest with the following code.
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class RegionExchangeRequest extends Model {
static associate(models) {
// define association here
}
};
RegionExchangeRequest.init({
region_id: DataTypes.INTEGER,
exchange_request_id: DataTypes.INTEGER
}, {
sequelize,
modelName: 'RegionExchangeRequest',
});
return RegionExchangeRequest;
};
I have a function that is doing the bulk insert on RegionExchangeReques as follow.
const create = async ({
exchange_rate,
currency,
amount,
buy_or_sell,
note,
email,
phone,
address,
region_ids,
userId
}) => {
try {
let exchangeRequest = await ExchangeRequest.create({
exchange_rate,
currency,
amount,
buy_or_sell,
note,
email,
phone,
address,
userId
});
if (region_ids && region_ids.length > 0) {
let pivotData = [ ];
region_ids.forEach(regionId => {
pivotData.push({
exchange_request_id: exchangeRequest.id,
region_id: regionId
})
})
let regionExchangeRequests = await RegionExchangeRequest.bulkCreate(pivotData);
}
return {
error: false,
data: exchangeRequest
}
} catch (e) {
return {
error: true,
code: 500,
message: e.message
}
}
}
When the function is called, it is throwing the following error.
"column \"id\" of relation \"RegionExchangeRequests\" does not exist"
The following line is throwing the error.
let regionExchangeRequests = await RegionExchangeRequest.bulkCreate(pivotData);
What is wrong with my code and how can I fix it?
In many-to-many relationship you specified RegionExchangeRequests as through table that connects two other tables, and in sequelize you cannot call usual model methods in through table.To do so you need to create super many-to-many relationship, for more information check out this link advanced-associations-in-sequelize

When creating a new element my foreignKey is always null. Sequelize, Node, Postgresql

I currently have a User model and a Team model that I want to associate.
User.js Model
"use strict";
module.exports = sequelize => {
const User = sequelize.define(
"User",
{
id: {
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV1,
primaryKey: true,
allowNull: false
},
...more fields
}
{ tableName: "Users", timestamps: true }
);
User.associate = function(models) {
// 1 to many with skill
User.hasMany(models.Skill, {
foreignKey: "userId"
});
// 1 to many with team
User.hasMany(models.Team, {
foreignKey: "userId"
});
};
return User;
};
Team.js Model
"use strict";
module.exports = (sequelize, DataTypes) => {
const Team = sequelize.define(
"Team",
{
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
...more fields
},
{ tableName: "Teams", timestamps: true }
);
Team.associate = function(models) {
Team.belongsTo(models.User, {
foreignKey: "userId"
});
};
return Team;
};
The column userId is automatically added to the team's table with the correct type (uuid) but no matter what I try it's always null.
I have tried just defining without options, and again the column was added, but set to null when a team was created.
1). Define the associations with no options.
User.associate = function(models) {
User.hasMany(models.Team);
}
Also, I have another table "Skills" that uses the same code but it works.
"use strict";
module.exports = (sequelize, DataTypes) => {
const Skill = sequelize.define(
"Skill",
{
id: {
type: DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true
},
},
{ tableName: "Skills", timestamps: true }
);
Skill.associate = models => {
Skill.belongsTo(models.User, {
foreignKey: "userId"
});
};
return Skill;
};
This is the method i'm using to create the team.
// Create a new team
exports.createTeam = async (req, res) => {
// Get the user id from the session
const userId = req.session.passport.user.id;
const { title } = req.body;
// Make sure the user hasn't already created a team with that title.
const existingTeam = await models.Team.findOne({
where: { title: title, userId: userId }
});
if (existingTeam !== null) {
// Response and let the user know.
...
return;
}
const defaultTeamValues = {
title: title,
...
};
// No existing team was found with that title and created by that user.
// Create it.
const team = await models.Team.create(defaultTeamValues);
// Done
res.status(200).json(team);
};
New record in Team's table showing null value in foreign key (userId) column.
I'm using pgAdmin 4 to view the tables and each table has the correct constraints fkeys too.
I feel like I'm missing something simple here, but I've read the docs and searched for similar issues but haven't found what I needed. What am I missing?
Ok, so I sort of figured out the problem. Instead of using
// Look for existing team
const existingTeam = await models.Team.findOne({
where: { title: title, userId: userId }
});
if (existingTeam !== null) {
...
return;
}
// No existing team was found with that title and created by that user.
// Create it.
const team = await models.Team.create(defaultTeamValues);
I switch to this method.
const team = await models.Team.findOrCreate({
where: {
title: title,
userId: userId
},
// title and userId will be appended to defaults on create.
defaults: defaultTeamValues
});
The difference being that findOrCreate will append, the values in the where query, to the default values you provide.
This is what I did previously when adding new skills and that's why my Skills records had the userId and Teams did not.
So at this point, I don't know if my associations are even working because I'm actually just adding the userId value into the new record.
Back to reading the docs and testing.

sequlize model cannot be fetched

I am using this scotch tutorial to create a basic node application using the sequelize js for ORM, here is my models/index.js:
and I am unable to use my user model with the user controller:
my model :
'use strict';
module.exports = (sequelize, DataTypes) => {
const user = sequelize.define('user', {
name: {
type : DataTypes.STRING,
allowNull : false
},
email: {
type: DataTypes.STRING,
allowNull: false
},
password: {
type: DataTypes.STRING,
allowNull: false
}
}, {});
user.associate = function(models) {
user.hasMany(models.wish, {
foreignKey: 'user_id',
as: 'wishes'
});
};
return user;
};
and here is my controller:
const user = require('../models').user;
module.exports = {
create(req, res){
return user.create({
name: req.body.name,
email: req.body.email,
password: req.body.password }).then(
todo => res.status(201).send(user)
).catch(
error => res.status(400).send(error)
);
}
}
but for some reason a big error comes on my screen and crashes the application, what I diagnosed from that error is that my controller is not able to find the 'user' model AND and I tried to link a bunch of things like giving the path to user directly but it did not work.
here is the error if you need (I am a newbee so could be totaly wrong about this)
I think you should change this line :
const user = require('../models').user;
to
const user = require('../models');

A is not associated to B

Looked on the internet about similar questions/errors, none of them helped me...
Unhandled rejection SequelizeEagerLoadingError: Task is not associated to User!
My users route
router.get('', function (req, res) {
models.User.findAll({
include: [
{
model: models.Task,
as: 'tasks'
}
]
}).then(function (users) {
res.send(users);
});
});
User model
'use strict';
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
first_name: DataTypes.STRING,
last_name: DataTypes.STRING,
email: DataTypes.STRING
}, {
underscored: true
});
User.associations = function (models) {
User.hasMany(models.Task, { as: 'tasks' });
};
return User;
};
Task model
'use strict';
module.exports = (sequelize, DataTypes) => {
const Task = sequelize.define('Task', {
name: DataTypes.STRING
}, {
underscored: true
});
Task.associations = function (models) {
Task.belongsTo(models.User);
};
return Task;
};
I associate them both, and made a bidirectional relationship..
As you are using the finder function for association with as option, Sequelize cannot find that alias, as it is not defined explicitly anywhere. Please try this one:
User.associations = function (models) {
User.hasMany(models.Task, { as: 'tasks' });
};
Hope this helps.

How to extend data-model with new method?

I use Sequelize to store and save data to a database.
var sequelize = require('../database.js').sequelize,
Sequelize = require('../database.js').Sequelize;
User = sequelize.define('user', {
authID: Sequelize.STRING,
name: Sequelize.STRING,
});
User.prototype.createRider = () => {
console.log('test');
};
module.exports = User;
I'm trying to extend the model with a new method to store a specific kind of user, but User.prototype.createRider doesn't work. What can be done?
There is an "expansion of models" section in their documentation
I believe you can use the classMethods object
var Foo = sequelize.define('foo', { /* attributes */}, {
classMethods: {
createRider: function(){ return 'smth' }
}
})
You can define both instance and class methods on your Model, during the define.
Change your sequelize.define as follows:
User = sequelize.define('user', {
authID: Sequelize.STRING,
name: Sequelize.STRING,
}, classMethods: {
createRider: function() {
console.log('test');
}
});
You can then use the classMethods in the expected way:
User.createRider();
See the Sequelize documentation: Model Definition.

Resources