Reputation: 389
I ran into a problem that I have not been able to solve for a week ...
When I pass the user's email to a query to the database, sequelize seems to do everything right and executes this query, it returns data from the table with the found result, but the result of executing the findOne
function is not a model, why did this happen and how can I fix it?
const email = '[email protected]'
const user = await User.findOne({ where: { email }})
console.log(user.password) // undefined
Here is the model, service and database connection
Model
import { DataTypes, Model } from "sequelize"
import { connection } from "./database"
class User extends Model {
readonly id: number
readonly email: string
password: string
username: string
readonly createdAt: Date
readonly updatedAt: Date
}
User.init(
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
email: {
type: DataTypes.STRING,
unique: true,
},
password: {
type: DataTypes.STRING,
},
username: {
type: DataTypes.STRING,
},
},
{
sequelize: connection,
modelName: "users",
createdAt: "created_at",
updatedAt: "updated_at",
}
)
export default User
Service
export async function loginUser(email: string, password: string): Promise<ServiceResponse<string>> {
try {
const user = await User.findOne({ where: { email } })
if (!user) {
throw Error("User not found")
}
if (!bcrypt.compareSync(password, user.password)) {
throw Error("User not found or password did not match")
}
const { password: _, ...payload } = user.toJSON()
const token = jwt.sign(payload, environment.jwt)
return { success: true, content: token }
} catch (error) {
return { success: false, error: error.message }
}
}
Database connection
import { Sequelize } from "sequelize"
import { environment } from "../environment"
export const connection = new Sequelize(environment.database, {
dialect: "postgres",
logging: console.log,
dialectOptions: {
ssl: {
rejectUnauthorized: false,
},
},
})
Here is log
Executing (default): SELECT "id", "email", "password", "username", "created_at", "updated_at" FROM "users" AS "users" WHERE "users"."email" = '[email protected]';
users {
dataValues: {
id: 9,
email: '[email protected]',
password: '$2b$10$s0HFL9eBbcp3GcGkB9cDZuSiCjOEgfQB5lZLxhxXraRfvRF6voDfW',
username: null,
created_at: 2020-11-16T13:09:30.631Z,
updated_at: 2020-11-16T13:09:30.631Z
},
_previousDataValues: {
id: 9,
email: '[email protected]',
password: '$2b$10$s0HFL9eBbcp3GcGkB9cDZuSiCjOEgfQB5lZLxhxXraRfvRF6voDfW',
username: null,
created_at: 2020-11-16T13:09:30.631Z,
updated_at: 2020-11-16T13:09:30.631Z
},
_changed: Set(0) {},
_options: {
isNewRecord: false,
_schema: null,
_schemaDelimiter: '',
raw: true,
attributes: [
'id',
'email',
'password',
'username',
'created_at',
'updated_at'
]
},
isNewRecord: false,
id: undefined,
email: undefined,
password: undefined,
username: undefined,
createdAt: undefined,
updatedAt: undefined
}
Used stack NextJS, Sequelize, PostgreSQL
What I'm doing wrong?
Upvotes: 1
Views: 8076
Reputation: 1
By default, Sequelize returns an instance of the model, which may contain some extra properties and methods specific to Sequelize models. To restrict it by doing so and in order to get only the specific model data you need to add raw:true , then you will be able to directly manipulate the model object. I'm attaching an example that how it would be worked.
Upvotes: 0
Reputation: 389
Thanks, the answer is Model.get({ plain: true })
before manipulating with received data.
Upvotes: 0
Reputation: 88
Model instances operate with the concept of a dataValues
property, which stores the actual values represented by the instance.
As you can see in your printout under dataValues
you have your model:
Executing (default): SELECT "id", "email", "password", "username", "created_at", "updated_at" FROM "users" AS "users" WHERE "users"."email" = '[email protected]';
users {
dataValues: {
id: 9,
email: '[email protected]',
password: '$2b$10$s0HFL9eBbcp3GcGkB9cDZuSiCjOEgfQB5lZLxhxXraRfvRF6voDfW',
username: null,
created_at: 2020-11-16T13:09:30.631Z,
updated_at: 2020-11-16T13:09:30.631Z
},
_previousDataValues: {
(...)
To get data from this dataValues
field you can use get
method.
Also findOne
return a promise.
So taking it together, in your case I think this should work
const email = '[email protected]'
User.findOne({ where: { email }}).then(data => {
console.log(data.get('password')
});
Take a look at Sequelize Model documentation
Upvotes: 1
Reputation: 136
Did you check your user object is it also undefined?
Try to do user.dataValues.password
to get password.
Or you can add raw: true
like this
const user = await User.findOne({ raw:true, where: { email }})
.Sequelize will return only data not the model instance. So you can use user.password
Upvotes: 1