Sequelize build is not a function when model is created from migration - node.js

This is my model which is create from sequelize cli: (it describes an user in User.js)
'use strict';
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
username: DataTypes.STRING
}, {});
User.associate = function(models) {
// associations can be defined here
};
return User;
};
When I try to create it in my script file, I get this following error:
User.build is not a function
Here's how I call the build method:
const User = require('../models/User');
User.build({
username: message["name"],
}).save();

In your case it returns a function not constructor
you have to pass sequelize and DataTypes while importing it
const User= require('../models/User')(sequelize, DataTypes);
Hope it'll work for you

You need to require model from "model/index"
so change this
const User = require('../models/User');
to this
const {User} = require('../models/index');
refer to this answer

Related

Sequelize - Model.create is not a function / Model.build is not a function

I'm creating an app with Node.js, Sequelize, Mysql, Express. I'm very new to this, sorry if this question is stupid.
I have two models with a one to many relation : User and Token (a user has multiple tokens, a token has one user).
Here are the files :
models/user.js
const { Sequelize, DataTypes } = require('sequelize');
const Token = require('./token')
const db = require('../db/sequelize'),
sequelize = db.sequelize,
jwt = require('jsonwebtoken')
// Model for a user (player)
const User = sequelize.define('User', {
// All the columns
})
User.gAuth = async function(user) {
const token = jwt.sign({id: user.id.toString() },
'password',
{
expiresIn: '7 days'
})
console.log(token)
console.log(Token)
const newToken = Token.create({
token,
user: this.id
})
console.log(newToken)
await newToken.save()
return token
}
module.exports = User
It's on "const newToken = Token.create({...})" that I have my error. It says : "Token.create is not a function". I tried with build, I had : "TypeError: Token.build is not a function".
models/token.js
const { Sequelize, DataTypes } = require('sequelize');
const db = require('../db/sequelize'),
sequelize = db.sequelize
const User = require('./user')
const Token = sequelize.define('Token', {
// All the columns
})
User.hasMany(Token, {
as: 'tokens'
})
Token.belongsTo(User, {
foreignKey: 'UserId',
as: 'user'
})
module.exports = Token
Can you please help me understands what I'm doing wrong ? All the answers I've found were about bad export of the Model, but I don't see my error.
Thank you !
EDIT :
When I console.log(sequelize.models) in models/token.js it returns : { User: User, Token: Token }
However ! When I console.log(sequelize.models) in models/user.js it retuns : { User: User }
Try this:
const { Sequelize, DataTypes } = require('sequelize');
const db = require('../db/sequelize'),
sequelize = db.sequelize,
jwt = require('jsonwebtoken')
const Token = require('./token')(sequelize, Sequelize)
Edit:
As per the docs instead of importing Token directly try grabbing the token off the sequelize instance like so:
const db = require('../db/sequelize'),
sequelize = db.sequelize,
jwt = require('jsonwebtoken')
const token = sequelize.models.Token
OKAY ! I found the thing I was doing wrong : structuring my files.
My function gAuth shouldn't have been on models/user.js but on models/token.js. Leaving it on user.js caused a circular dependency which was causing the bug.
I've removed gAuth from user.js, moved it to token.js and removed the require('./token') from user.js
I hope this can help some people with the same problem !
Thanks a lot to #about14sheep for helping me out.

Cannot read property 'create' of undefined in expressjs

Please am new to Nodejs but am trying to insert a data into my database using sequelize but am getting Cannot read property .create of undefined.
This is my index.js file
const fs = require('fs')
const path = require('path')
const Sequelize = require('sequelize')
const config = require('../config/config')
const db = {}
const sequelize = new Sequelize(
config.DB,
config.USER,
config.PASSWORD,
{
host: config.HOST,
dialect: config.dialect,
operatorsAliases: false,
pool: {
max: config.pool.max,
min: config.pool.min,
acquire: config.pool.acquire,
idle: config.pool.idle
}
});
fs
.readdirSync(__dirname)
.filter((file) =>
file !== 'index.js'
)
.forEach((file) => {
const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes)
// db[model] = model
db.User = model
})
db.sequelize = sequelize
db.Sequelize = Sequelize
module.exports = db;
This is my Model/User.js File
module.exports = (sequelize, DataTypes) => {
sequelize.define('User', {
hmtec_email: {
type: DataTypes.STRING,
unique: true
},
hmtec_password: DataTypes.STRING
})
This is my Controllers/AuthController.js File
const {User} = require ('../models/User')
module.exports = {
async register (req, res) {
try {
const user = await User.create(req.body)
res.send(user.toJSON())
} catch (err) {
console.log(err);
res.status(400).send({
error: 'Email already in Use'
})
}
}
I don't know what wrong with the code, I dont know why am getting that error of .create is undefined
I think your problem is in the last file .. AuthController.js
const {User} = require ('../models/User')
You are using the Es6 new destruction assignment
More Info here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
Normally you should define your variable without the brackets
That mean you got all of the variable available.
But adding the brackets means that you want to get the child of the object, this child is named user .. and then name the variable also as user
and search these info
From the require file after the equal.
But in your user file .. you are exporting a function .. that does not have any child named user
Thus undefined
Better alternative is to use Classes
More info here : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
So in user model
// Inside your function you need to use sequalize module , iam not familar with it but you must require it to use it
const Sequelize = require('sequelize');
// Define the Class
class user {
// add the name you want to use for the function - here I used create so the other code also work - also I inserted async because this is asynchronous and also I removed the sequalize from parameters because you don't need it now after it is required above.
async create (DataTypes) => {
await Sequelize.define('User', {
hmtec_email: {
type: DataTypes.STRING,
unique: true
},
hmtec_password: DataTypes.STRING
})
}
module.exports = user;
Now when you require the file in Authcontroller , remove the brackets
const User = require ('../models/User')
and now you can use User.create(YOUR_DATA_VARIABLE);in your authController.js
and if there is any other functions inside this class you also can use them in the same manner.
I hope this fix your problem.

Sequelize doesn't read the new modelname after I do refactor (remove s in end modelname)

I've a backend app built in Express with Sequelize ORM.
Here is my code;
user.js (model)
'use strict';
module.exports = (sequelize, DataTypes) => {
const user = sequelize.define('user', {
username: DataTypes.STRING,
}, {
// tableName: 'user'
});
user.associate = function(models) {
// associations can be defined here
};
return user;
};
user.js (controller):
const User = require('../models').user;
module.exports = {
getUser: function (req, res) {
User.findAll().then(value => {
res.json(value);
})
}
}
When I start the project, it return error Unhandled rejection SequelizeDatabaseError: relation "users" does not exist. As you can see my code above, I've set the model as user not users, and the table in db also user not users. It's only work fine if I add the tableName: 'user' in the model file.
NOTE: By the default, when I do create model with sequelize, the file name and model define is users, but I refactor file name and define inside model into user
Why does this happen?
This is default behavior - Sequelize automatically transforms model name to plural. In order to disable that you should freeze table name in model definition (or just set table name explicitly like you are actually doing):
freezeTableName: true,

How to get model from sequelize.model after use sequelize-cli

I use sequelize-cli to auto generate code for model Student:
module.exports = (sequelize, DataTypes) => {
var _stu = sequelize.define('stu', {
name: DataTypes.STRING,
password: DataTypes.STRING,
gender: DataTypes.INTEGER,
}, {
classMethods: {
associate: function(models) {
// associations can be defined here
}
}
});
return _stu
};
My question are
How to get model named stu? As the sequelize is defined in function signature.
When sequelize model:generate,sequelize read config in config.json,where dbname,passowrd are specified.
How the sequelize in the function signature knows database connection config,say,name,password,etc as I don't specify in this js file.
Answer for question 1:
"sequelize.import" will do this job.
Try this code:
const Sequelize = require('sequelize')
const sequelize = new Sequelize(...)
const stu = sequelize.import('./models/stu')
stu.findAll.then(...)
When you generate models via the CLI, it creates a handy models/index.js file that handles passing in a Sequelize instance for you. You can simply require cherry picked, existing models via ES6 destructuring like this:
var { stu } = require("./models");
stu.findAll().then(...);
Alternatively, you could require them all at once, and then access specific models as needed:
var models = require("./models");
models.stu.findAll().then(...);
The way i make it works was importing model with the require() function and then call it with required parameters.
Explanation
By require function you will get another function that returns your model.
module.exports = (sequelize, DataTypes) => {
const stu = sequelize.define('stu', {
// ...database fields
}, {});
stu.associate = function(models) {
// associations can be defined here
};
return sty;
} // note that module.exports is a function
Now, this function requires the initialized sequelize object and a DataTypes object, so you just have to pass the instance of sequelize and Sequelize.DataTypes and then it will return your model, example:
const Sequelize = require('sequelize');
const sequelize = new Sequelize(...);
const Stu = require('./models/stu')(sequelize, Sequelize.DataTypes);
Finally you can get your database rows with Stu.findAll().
Hope this can help you.

Sequelize: Require vs Import

In the documentation for sequlize they use the import function like so
// in your server file - e.g. app.js
var Project = sequelize.import(__dirname + "/path/to/models/project")
// The model definition is done in /path/to/models/project.js
// As you might notice, the DataTypes are the very same as explained above
module.exports = function(sequelize, DataTypes) {
return sequelize.define("Project", {
name: DataTypes.STRING,
description: DataTypes.TEXT
})
}
However, what would be so wrong with this?
// in your server file - e.g. app.js
var Project = require(__dirname + "/path/to/models/project")
// The model definition is done in /path/to/models/project.js
var Project = sequelize.define("Project", {
name: Sequelize.STRING,
description: Sequelize.TEXT
});
module.exports = Project
Well, as you can see your model definition needs two things:
Sequelize or DataTypes
sequelize
In your first example when using sequelize.import('something'); it is similar to use require('something')(this, Sequelize); (this being the sequelize instance)
Both are necessary to initialize your model, but the important thing to understand is: One of these is a classtype so it's global, the other one is an instance and has to be created with your connection parameters.
So if you do this:
var Project = sequelize.define("Project", {
name: Sequelize.STRING,
description: Sequelize.TEXT
});
module.exports = Project
Where does sequelize come from? It has to be instantiated and passed somehow.
Here is an example with require instead of import:
// /path/to/app.js
var Sequelize = require('sequelize');
var sequelize = new Sequelize(/* ... */);
var Project = require('/path/to/models/project')(sequelize, Sequelize);
// /path/to/models/project.js
module.exports = function (sequelize, DataTypes) {
sequelize.define("Project", {
name: DataTypes.STRING,
description: DataTypes.TEXT
});
};
module.exports = Project
You could even change it so you wouldn't have to pass Sequelize by requiring it in the model itself, but you would still need to create a sequelize instance prior to define the model.
sequelize.import is deprecated as of sequelize 6
As mentioned at https://sequelize.org/master/manual/models-definition.html
Deprecated: sequelize.import
Note: You should not use sequelize.import. Please just use require instead.
So you should just port:
// index.js
const sequelize = new Sequelize(...)
const User = sequelize.import('./user')
// user.js
module.exports = (sequelize, DataTypes) => {
// Define User.
return User;
}
to:
// index.js
const sequelize = new Sequelize(...)
const User = require('./user')(sequelize)
// user.js
const { DataTypes } = require('sequelize')
module.exports = (sequelize) => {
// Define User.
return User;
}

Resources