I was trying to make an API using Node.js and Sequelize (MySQL). The API has many models and associations. I made migrations after making the models. Now that I'm making the service file, when I make a request to the login route, I encounter that error. I have tried many things and read a lot of guides for this issue. But I still have that.
(Typos checked!) -- (The modules imported properly)
Could you please suggest me a solution? I appreciate you in advance!
Error
const results = await db.user.findOne({where:{phoneNumber: body.phoneNumber}})
^
TypeError: Cannot read properties of undefined (reading 'findOne')
at login (C:\Users\Ali\Desktop\Learning\Mafia-api\user\user.service.js:5:35)
at Layer.handle [as handle_request] (C:\Users\Ali\Desktop\Learning\Mafia-api\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\Ali\Desktop\Learning\Mafia-api\node_modules\express\lib\router\route.js:144:13)
at Route.dispatch (C:\Users\Ali\Desktop\Learning\Mafia-api\node_modules\express\lib\router\route.js:114:3)
at Layer.handle [as handle_request] (C:\Users\Ali\Desktop\Learning\Mafia-api\node_modules\express\lib\router\layer.js:95:5)
at C:\Users\Ali\Desktop\Learning\Mafia-api\node_modules\express\lib\router\index.js:284:15
at Function.process_params (C:\Users\Ali\Desktop\Learning\Mafia-api\node_modules\express\lib\router\index.js:346:12)
at next (C:\Users\Ali\Desktop\Learning\Mafia-api\node_modules\express\lib\router\index.js:280:10)
at Function.handle (C:\Users\Ali\Desktop\Learning\Mafia-api\node_modules\express\lib\router\index.js:175:3)
at router (C:\Users\Ali\Desktop\Learning\Mafia-api\node_modules\express\lib\router\index.js:47:12)
[nodemon] app crashed - waiting for file changes before starting...
Model: user.js
module.exports = async (sequelize, DataTypes) => {
const user = await sequelize.define('users', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true,
},
phoneNumber: {
type: DataTypes.STRING(20),
allowNull: false,
unique: true
},
displayName: {
type: DataTypes.STRING,
allowNull: false,
unique: true
}
})
user.association = model => {
user.hasMany(model.currencyWallet);
user.hasMany(model.userSetting);
}
return user
}
Service: user.service.js
const db = require('../models');
async function login(req, res) {
const body = req.body;
const results = await db.user.findOne({where:{phoneNumber: body.phoneNumber}})
res.json({
success: 0,
message: 'Results found!'
})
}
module.exports = {
login
}
Index.js
const express = require('express');
const app = express();
const userRouter = require('./user/user.router');
const PORT = 5000
const HOST = 'localhost'
const db = require('./models');
app.use(express.json());
app.use('/', userRouter);
db.sequelize.sync().then(() => {
app.listen(PORT, () => console.log(`Server running on http://${HOST}:${PORT}`));
})
config.json
"development": {
"username": "xxxx",
"password": xxxx,
"database": "nameofthegamegoeshere",
"host": "xxx.x.x.x",
"dialect": "mysql"
}
I fortunately found the solution of my problem myself!
It took me a lot of time and effort to find the problem and debug it but it's not a very complicated problem!
In one of my models, user.js that I mentioned earlier, I was using async/await syntax to define a table.
IT'S NOT TRUE ...
After I removed the async/await from my model, user.js file, the problem gone away!
So, user.js should be like this (without any async/await expression):
module.exports = (sequelize, DataTypes) => {
const user = sequelize.define('users', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true,
},
phoneNumber: {
type: DataTypes.STRING(20),
allowNull: false,
unique: true
},
displayName: {
type: DataTypes.STRING,
allowNull: false,
unique: true
}
})
user.association = model => {
user.hasMany(model.currencyWallet);
user.hasMany(model.userSetting);
}
return user
}
This problem occurred because I had some issue to understand how Javascript Promises work.
I recommend to read more about 1- Callback functions and 2- Promises respectively in order to understand the issue and it's solution. Specially if you're also a beginner like me :)
This is one of the useful resources to check:
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Promises
When I use async/await to make a model, It returns a Promise.
const user = await sequelize.define('users', {some-code-in-here})
Then the promise state turns to <"pending">. It means that something is on process or we are waiting...
Because the state of that promise is on "pending", no result object would be expected to be in user and as the result, the value of user will be undefined.
This is the reason that the error says: "It can't read properties of undefined".
Once the promise state turns to "settled", it will return a result (when succeeds) or an error (when fails).
But in this case, the state of that promise is still on "pending" when the program use it as user.
By removing async/await, it will immediately executes the define() function and put the result in user. So there is no problem to make use of user anymore.
~ I hope this post can help to solve many people's problem and saves a lot of time :) ~