I'm using Sequelize to do a DB find for a user record, and I want the default behavior of the model to not return the password
field for that record. The password
field is a hash but I still don't want to return it.
I have several options that will work, but none seems particularly good:
Create a custom class method
findWithoutPassword
for theUser
model and within that method do aUser.find
with theattributes
set as shown in the Sequelize docsDo a normal
User.find
and filter the results in the controller (not preferred)Use some other library to strip off unwanted attributes
Is there a better way? Best of all would be if there is a way to specify in the Sequelize model definition to never return the password
field, but I haven't found a way to do that.
I would suggest overriding the toJSON
function:
sequelize.define('user', attributes, {
instanceMethods: {
toJSON: function () {
var values = Object.assign({}, this.get());
delete values.password;
return values;
}
}
});
Or in sequelize v4
const User = sequelize.define('user', attributes, {});
User.prototype.toJSON = function () {
var values = Object.assign({}, this.get());
delete values.password;
return values;
}
toJSON
is called when the data is returned to the user, so end users won't see the password field, but it will still be available in your code.
Object.assign
clones the returned object - Otherwise you will completely delete the property from the instance.
Another way is to add a default scope to the User model.
Add this in the model's options object
defaultScope: {
attributes: { exclude: ['password'] },
}
Or you can create a separate scope to use it only in certain queries.
Add this in the model's options object
scopes: {
withoutPassword: {
attributes: { exclude: ['password'] },
}
}
Then you can use it in queries
User.scope('withoutPassword').findAll();
Maybe you can just add exclude
at your attribute when you find
, look like this:
var User = sequelize.define('user', attributes);
User.findAll({
attributes: {
exclude: ['password']
}
});
Read the docs for more details
I like to use a combination of both of Pawan's answers and declare the following:
defaultScope: {
attributes: { exclude: ['password'] },
},
scopes: {
withPassword: {
attributes: { },
}
}
This allows me to exclude the password by default and use the withPassword
scope to explicitly return the password when needed, such as when running a login method.
userModel.scope('withPassword').findAll()
This ensure that the password is not returned when including the user via a referenced field, e.g.
accountModel.findAll({
include: [{
model: userModel,
as: 'user'
}]
})
there's a plugin for scoping attributes as discussed here.
i went with the override as mentioned in the accepted answer, except i called the original toJSON
rather than get
with this.constructor.super_.prototype.toJSON.apply(this, arguments)
as described in the api docs
The code below worked for me. We wanted access to the instance attributes at runtime but remove them before sending the data to the client.
const Sequelize = require('sequelize')
const sequelize = new Sequelize('postgres://user:pass@example.com:5432/dbname')
const PROTECTED_ATTRIBUTES = ['password', 'token']
const Model = Sequelize.Model
class User extends Model {
toJSON () {
// hide protected fields
let attributes = Object.assign({}, this.get())
for (let a of PROTECTED_ATTRIBUTES) {
delete attributes[a]
}
return attributes
}
}
User.init({
email: {
type: Sequelize.STRING,
unique: true,
allowNull: false,
validate: {
isEmail: true
}
},
password: {
type: Sequelize.STRING,
allowNull: false
},
token: {
type: Sequelize.STRING(16),
unique: true,
allowNull: false
},
},
{
sequelize,
modelName: 'user'
})
module.exports = User
来源:https://stackoverflow.com/questions/27972271/sequelize-dont-return-password