我使用Sequelize为用户记录执行数据库查找,我希望模型的默认行为不返回该记录的password
字段。 password
字段是哈希,但我仍然不想退回。
我有几个选项可行,但似乎没有一个特别好:
为findWithoutPassword
模型创建自定义类方法User
,并在该方法中执行User.find
设置attributes
,如{{3}所示}}
执行正常User.find
并过滤控制器中的结果(不是首选)
使用其他库删除不需要的属性
有更好的方法吗?最重要的是,如果有一种方法可以在Sequelize模型定义中指定永远不会返回password
字段,但我还没有找到方法来做到这一点。
答案 0 :(得分:56)
我建议覆盖toJSON
函数:
sequelize.define('user', attributes, {
instanceMethods: {
toJSON: function () {
var values = Object.assign({}, this.get());
delete values.password;
return values;
}
}
});
或者在sequelize v4中
const User = sequelize.define('user', attributes, {});
User.prototype.toJSON = function () {
var values = Object.assign({}, this.get());
delete values.password;
return values;
}
将数据返回给用户时会调用 toJSON
,因此最终用户无法看到密码字段,但仍会在您的代码中显示。
Object.assign
克隆返回的对象 - 否则您将从实例中完全删除该属性。
答案 1 :(得分:39)
另一种方法是向用户模型添加默认范围。
在模型的选项对象
中添加它defaultScope: {
attributes: { exclude: ['password'] },
}
或者您可以创建单独的范围,仅在某些查询中使用它。
在模型的选项对象
中添加它scopes: {
withoutPassword: {
attributes: { exclude: ['password'] },
}
}
然后你可以在查询中使用它
User.scope('withoutPassword').findAll();
答案 2 :(得分:23)
也许您可以在exclude
时在属性中添加find
,如下所示:
var User = sequelize.define('user', attributes);
User.findAll({
attributes: {
exclude: ['password']
}
});
阅读docs了解更多详情
答案 3 :(得分:9)
我喜欢结合使用Pawan的两个答案,并声明以下内容:
defaultScope: {
attributes: { exclude: ['password'] },
},
scopes: {
withPassword: {
attributes: { },
}
}
这使我默认情况下可以排除密码,并使用withPassword
范围在需要时(例如在运行登录方法时)显式返回密码。
userModel.scope('withPassword').findAll()
这样可以确保在通过引用字段(例如,
)包含用户时不返回密码。accountModel.findAll({
include: [{
model: userModel,
as: 'user'
}]
})
答案 4 :(得分:0)
已经讨论了scoping attributes here的插件。
我接受了接受回答中提到的覆盖,除了api docs
toJSON而不是get
this.constructor.super_.prototype.toJSON.apply(this, arguments)
>
答案 5 :(得分:0)
以下代码对我有用。我们希望在运行时访问实例属性,但在将数据发送到客户端之前将其删除。
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
答案 6 :(得分:0)
我可以通过在返回undefined
的字段中添加一个吸气剂来解决这个问题。
firstName: {
type: DataTypes.STRING,
get() {
return undefined;
}
}
当模型包含在另一个模型中时,accepted answer不起作用。
我有一个虚拟字段,例如fullName
,它取决于我要隐藏的字段,例如firstName
和lastName
。并且基于defaultScope
的{{3}}在这种情况下不起作用。
答案 7 :(得分:0)
您可以通过排除属性以简单的方式执行此操作。参见下面的代码(注释行)
Patient.findByPk(id, {
attributes: {
exclude: ['UserId', 'DiseaseId'] // Removing UserId and DiseaseId from Patient response data
},
include: [
{
model: models.Disease
},
{
model: models.User,
attributes: {
exclude: ['password'] // Removing password from User response data
}
}
]
})
.then(data => {
res.status(200).send(data);
})
.catch(err => {
res.status(500).send({
message: `Error retrieving Patient with id ${id} : ${err}`
});
});