everyone. I'm very new for sequelize ORM with nodejs.
I've just created couple files for models seperately and I also seperate sequelize.js to connect to database.
The problem is when I make association between model(file)(Self Associate work well) and I've got an error
**** "hasMany called with something that's not a subclass of Sequelize.Model"
I tried to solved this but doesn't work until I put every model in the same file. So, I realized that every model must use common sequelize connection.
Is there anyways to solve this problem without sequelize-cli (I don't want to use sequelize-cli)
My code belows
Many thanks,
sequelize.js
const config = require("config");
const { Sequelize } = require("sequelize");
const sequelize = new Sequelize(
config.get("database"),
config.get("user"),
config.get("cipher"),
{
dialect: "mariadb",
timezone: "Asia/Bangkok",
}
);
module.exports = sequelize;
user.js
const { DataTypes, Model } = require("sequelize");
const sequelize = require("./sequelize");
const Position = require("./position");
class User extends Model {}
User.init(
{
uuid: {
type: DataTypes.UUID,
allowNull: false,
defaultValue: DataTypes.UUIDV4,
},
title: {
type: DataTypes.STRING,
allowNull: false,
},
firstname: {
type: DataTypes.STRING,
allowNull: false,
},
lastname: {
type: DataTypes.STRING,
allowNull: false,
},
phone: {
type: DataTypes.STRING,
allowNull: true,
},
email: {
type: DataTypes.STRING,
allowNull: true,
validate: {
isEmail: true,
},
},
imgurl: {
type: DataTypes.STRING,
allowNull: true,
},
login: {
type: DataTypes.STRING,
allowNull: false,
},
passphase: {
type: DataTypes.STRING,
allowNull: false,
},
status: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 1,
},
},
{
sequelize,
modelName: "User",
tableName: "users",
timestamps: true,
}
);
User.belongsToMany(User, {
as: "CreatedUser",
foreignKey: "user_id",
through: "UserCreator",
});
User.belongsToMany(User, {
as: "Creator",
foreignKey: "creator_id",
through: "UserCreator",
});
User.belongsToMany(User, {
as: "ModifiedUser",
foreignKey: "user_id",
through: "UserModifier",
});
User.belongsToMany(User, {
as: "Modifier",
foreignKey: "modifier_id",
through: "UserModifier",
});
User.belongsTo(Position);
module.exports = User;
position.js
const { DataTypes, Model } = require("sequelize");
const sequelize = require("./sequelize");
const User = require("./user");
class Position extends Model {}
Position.init(
{
uuid: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
status: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 1,
},
},
{
sequelize,
modelName: "Position",
tableName: "postions",
timestamps: true,
}
);
Position.hasMany(User, {
foreignKey: {
type: DataTypes.UUIDV4,
allowNull: false,
},
});
module.exports = Position;
Sequelize has a .define() method to create all your schemas in JSON. If you want to keep your connection to the database separate from your models, I suggest doing something like this
./models/schemas/User.js
const userSchema = {
attribute1: {
type: ...,
option1: ...,
option2: ...,
.
.
},
.
.
}
export default userSchema
Do the same with Position.js
Then:
./models/models.js
import {sequelize} from 'path/to/sequelize.js'
import positionSchema from './schemas/Position.js'
import userSchema from './schemas/User.js'
const User = sequelize.define("user", userSchema, { freezeTableName: true });
const Position = sequelize.define("position", positionSchema, { freezeTableName: true });
// add associations
export {
User,
Position,
.
.
}
Related
My sequelize migration file being referenced in terminal:
Sequelize CLI [Node: 16.10.0, CLI: 6.2.0, ORM: 6.7.0]
Loaded configuration file "db\config.js".
Using environment "development".
== 20211021030720-create-customers: migrating =======
ERROR: Cannot read properties of undefined (reading 'toString')
This is my model file:
const { Model, DataTypes, Sequelize } = require('sequelize');
const { USER_TABLE } = require('./user.model');
const CUSTOMER_TABLE = 'customers';
const CustomerSchema = {
costomerId: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
customerName: {
allowNull: false,
type: DataTypes.STRING,
},
customerLastname: {
allowNull: false,
type: DataTypes.STRING,
},
customerPhone: {
allowNull: true,
type: DataTypes.STRING,
},
createdAt: {
allowNull: false,
type: DataTypes.DATE,
field: 'create_at',
defaultValue: Sequelize.NOW,
},
userId: {
field: 'user_id',
allowNull: false,
type: DataTypes.INTEGER,
references: {
model: USER_TABLE,
key: 'userId'
},
onUpdate: 'CASCADE',
onDelete: 'SET NULL'
}
}
class Customer extends Model {
static associate(models) {
this.belongsTo(models.User, {as: 'user'});
}
static config(sequelize) {
return {
sequelize,
tableName: CUSTOMER_TABLE,
modelName: 'Customer',
timestamps: false
}
}
}
module.exports = { CUSTOMER_TABLE, CustomerSchema, Customer };
Other posts mention that it can be caused by an invalid property of DataTypes but I have already checked the code several times and I cannot find the problem.
If other information to help solve, please ask for it.
EDIT
I realized that I wrote .addColumn instead .createTable. Now everything is working properly.
module.exports = {
up: async (queryInterface) => {
await queryInterface.createTable(CUSTOMER_TABLE, CustomerSchema);
},
In my application every user can record many temperatures, but one temperature record should have only one user. I am trying to execute the following code and facing an 'User is not associated with Temperature' Error. Please review my code below and let me know where i have gone wrong.
This is my User model
const { Sequelize, DataTypes, Model } = require('sequelize');
const sequelize = require('../connection');
var Temperature = require('./temperature');
var User = sequelize.define('User', {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true,
},
firstName: {
type: DataTypes.STRING,
allowNull: false
},
lastName: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false
},
password: {
type: DataTypes.STRING,
allowNull: false
},
status: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: 'Active'
},
role: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: 'Admin'
}
});
User.associate = (models) => {
User.hasMany(models.Temperature, { as: 'temperatures' })
}
module.exports = User;
This is my Temperature model
const { Sequelize, DataTypes, Model } = require('sequelize');
const sequelize = require('../connection');
const User = require('./users');
var Temperature = sequelize.define('Temperature', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
userId: {
type: DataTypes.INTEGER,
allowNull: false,
},
temperature: {
type: DataTypes.FLOAT,
allowNull: false
},
recordDateTime: {
type: DataTypes.DATE,
allowNull: false
}
});
Temperature.associate = (models) => {
Temperature.belongsTo(models.User, { foreignKey: 'userId', as: 'user' })
}
module.exports = Temperature;
I am getting error in running the following code
Temperature.findAll({ include: User, raw:true})
.then((res)=>{
console.log(res);
})
Can you anyone please help in figuring out this issue.
The associate functions in both the models are not executing.
you don't need to add userId column into Temperature model schema, just define associations as you have already did and even if you want to add userId column in model schema the do it like below but must add it in migration file of your Temperature model schema like below
userId: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'Users', // <----- name of the table
key: 'id' // <----- primary key
}
}
Hi everyone I'm having an error "Error: Text.belongsTo called with something that's not a subclass of Sequelize.Model" when I add association of Sequelize in my model it called an error that what I call is not Sequelize Model.
Here is the code of my models, I try to create an association between Post model and Text model.
./Post.js
const { DataTypes } = require('sequelize');
const sequelize = require('../../db/sequelize.setup');
const Text = require('./Text');
const Post = sequelize.define(
'Post',
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false,
},
title: {
type: DataTypes.STRING(),
allowNull: false,
},
tags: {
type: DataTypes.ARRAY(DataTypes.INTEGER),
allowNull: true,
},
items: {
type: DataTypes.ARRAY(DataTypes.INTEGER),
allowNull: false,
},
author: {
type: DataTypes.INTEGER,
},
},
{
modelName: 'Post',
timestamps: true,
}
);
Post.hasMany(Text, {
as: 'Text',
foreignKey: 'post_id',
sourceKey: 'id',
});
module.exports = Post;
./Text.js
const { DataTypes } = require('sequelize');
const sequelize = require('../../db/sequelize.setup');
const Post = require('./Post');
const Text = sequelize.define(
'Text',
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false,
},
text: {
type: DataTypes.STRING(),
allowNull: false,
},
},
{
modelName: 'Text',
timestamps: true,
}
);
Text.belongsTo(Post, { as: 'Post', foreignKey: 'post_id', targetKey: 'id' });
module.exports = Text;
try to make an index.js file in your models folder and inside of it make your association like this
const db = {};
db.Sequelize = Sequelize;
db.sequelize = sequelize;
db.posts=require("./post.js")(sequlize,sequlize);
db.texts=require....
db.posts.hasMany(db.texts, { foreignKey: 'postId' });
db.texts.belongsTo(db.posts, { foreignKey: 'postId' });
and put the postId in text.js model
I'm using Sequelize connected to PostgreSQL and as I want to use sync function I would like to prepare valid models to create tables on every environment.
EDIT:
Wallet:
'use strict';
module.exports = function(db, DataTypes) {
var Wallet = db.define('Wallet', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true
},
money: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
}
createdAt: DataTypes.DATE,
updatedAt: DataTypes.DATE
}, {
tableName: 'wallet',
classMethods:{
associate : function( models ) {
Wallet.belongsTo( models.User,{ foreignKey : 'id_user'});
}
}
});
return Wallet;
};
User:
'use strict';
var bcrypt = require('bcrypt-nodejs');
var crypto = require('crypto');
var moment = require('moment');
var models = require('./');
var afterCreateHook = function(user, options, fn) {
models.Wallet.build({id_user: user.id}).save();
fn(null, user);
};
module.exports = function(db, DataTypes) {
var User = db.define('User', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true
},
password: DataTypes.STRING,
email: {
type: DataTypes.STRING,
unique: true,
allowNull: false,
isEmail: true
},
login: {
type: DataTypes.STRING,
unique: true,
allowNull: false
}
}, {
tableName: 'pl_users',
instanceMethods: instanceMethods,
classMethods: {
associate : function( models ) {
User.hasOne( models.Wallet);
}
},
hooks: {
afterCreate: afterCreateHook
}
});
return User;
};
Why
models.Wallet.build({id_user: user.id}).save();
is not working? Account is creating and then I want to create wallet with specific user_id. I don't have even an error...
Help please!
You should check relations from sequelize docs
In your case youu need to define:
Wallet.belongsTo(User,{foreignKey: 'id_user'});
This will add id_user to Wallet model , so you dont need to specify id_user attribute in your WalletModel.
If you are using sequelize import function , you should add the relation in "associate" class method like this:
module.exports = function(db, DataTypes) {
var Wallet = db.define('Wallet', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true
},
pin: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
},
money: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: 0
},
createdAt: DataTypes.DATE,
updatedAt: DataTypes.DATE
}, {
tableName: 'Wallet',
classMethods:{
associate : function( models ) {
Wallet.belongsTo( models.User,{ foreignKey : 'id_user'});
}
}
});
I've been through several questions on the site but I still can't see what I'm doing wrong here, so any help would be greatly appreciated.
I'm getting the error:
Organization (organizations) is not associated to User!
Org Model:
module.exports = function (sequelize, DataTypes) {
return sequelize.define('Organization', {
organizationID: {
primaryKey: true,
type: DataTypes.INTEGER(11),
allowNull: false,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
description: {
type: DataTypes.STRING,
allowNull: true,
}
},
{
tableName: "spa_vOrganization",
freezeTableName: true,
classMethods: {
associate: function (models) {
Organization.hasMany(models.User, {
as: 'users',
through: models.User_Tenant_Organization,
foreignKey: 'organizationID'
});
}
},
});
};
User Model:
module.exports = function (sequelize, DataTypes) {
return sequelize.define('User', {
userID: {
primaryKey: true,
type: DataTypes.INTEGER(11),
allowNull: false,
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
}
},
{
tableName: "spa_User",
freezeTableName: true,
classMethods: {
associate: function(models) {
User.hasMany(models.Organization, { as: "organizations", through: models.User_Tenant_Organization, foreignKey: 'userID'});
}
}
}
);
};
Matrix table model:
module.exports = function (sequelize, DataTypes) {
return sequelize.define('User_Tenant_Organization', {
userTenantOrganizationID: {
primaryKey: true,
type: DataTypes.INTEGER(11),
allowNull: false,
},
userID: {
type: DataTypes.INTEGER(11),
allowNull: false,
},
organizationID: {
type: DataTypes.INTEGER(11),
allowNull: false,
},
tenantID: {
type: DataTypes.INTEGER(11),
allowNull: false,
},
},
{
tableName: "spa_User_Tenant_Organization",
freezeTableName: true,
});
};
What I'm trying to do is just pull back a user with their organizations eagerly loaded. Here's what I'm using:
models.User.findOne({where: {
email: body.email
}, include: [ {model:models.Organization, as: 'organizations'}]}).complete( function (err, user) {
// do something with the user
}
I've tried with and without foreignKey definitions on both User and Organization, nothing makes any difference. I'm obviously misunderstanding something about the associations. Can anyone tell me where I'm going wrong please?
I found the problem. The associations in the above code are actually correct - what was failing was my models/index.js, which had been automatically generated by the yeoman generator-angular-express-sequelize
index.js was looping through the model files, importing them into the sequelize object and storing a copy in an array db[], then trying to run the classMethod associate(), but it was calling models.options.associate() instead of models.associate():
Object.keys(db).forEach(function (modelName) {
if (db[modelName].options.hasOwnProperty('associate')) {
db[modelName].options.associate(db);
}
});
I've fixed that by removing the ".options" and everything works fine.
Pull request to fix the problem is here for reference: https://github.com/rayokota/generator-angular-express-sequelize/pull/7