使用 Mongoose Schema 防止字段修改
Posted
技术标签:
【中文标题】使用 Mongoose Schema 防止字段修改【英文标题】:Prevent field modification with Mongoose Schema 【发布时间】:2018-11-05 17:43:38 【问题描述】:当你定义一个新的 Mongoose Schema 时,有什么方法可以设置一个“不可修改”设置的字段(例如类型、必需等)?这意味着一旦创建了新文档,就无法更改此字段。
例如,像这样的:
var userSchema = new mongoose.Schema(
username:
type: String,
required: true,
unmodifiable: true
)
【问题讨论】:
【参考方案1】:从 Mongoose 5.6.0 版本开始,我们可以在模式中使用immutable: true
(与前面提到的mongoose-immutable
包上的答案完全相同)。典型的用例是时间戳,但在你的情况下,username
是这样的:
const userSchema = new mongoose.Schema(
username:
type: String,
required: true,
immutable: true
);
如果您尝试更新该字段,Mongoose 将忽略修改。
比 OP 的要求更进一步,现在有了 Mongoose 5.7.0,我们可以有条件地设置 immutable
属性。
const userSchema = new mongoose.Schema(
username:
type: String,
required: true,
immutable: doc => doc.role !== 'ADMIN'
,
role:
type: String,
default: 'USER',
enum: ['USER', 'MODERATOR', 'ADMIN'],
immutable: true
);
来源:What's New in Mongoose 5.6.0: Immutable Properties 和 What's New in Mongoose 5.7: Conditional Immutability, Faster Document Arrays。
【讨论】:
【参考方案2】:您只能在 userSchema.pre
save
中使用 Mongoose:
if (this.isModified('modified query'))
return next(new Error('Trying to modify restricted data'));
return next();
【讨论】:
【参考方案3】:我在修改字段时遇到了同样的问题。
试试https://www.npmjs.com/package/mongoose-immutable-plugin
插件将拒绝对字段的每次修改尝试,它适用于
-
更新
UpdateOne
FindOneAndUpdate
UpdateMany
重新保存
它支持数组、嵌套对象等类型的字段并保护深度不变性。
插件还将更新选项处理为 $set、$inc 等。
【讨论】:
【参考方案4】:请注意,文档明确指出,在使用带有更新标识符/名称的函数时,不会触发“pre”中间件:
虽然在使用更新时会将值转换为相应的类型,但以下内容不适用: - 默认值 - 二传手 - 验证器 - 中间件
如果您需要这些功能,请使用首先检索文档的传统方法。
Model.findOne( name: 'borne' , function (err, doc) if (err) .. doc.name = 'jason bourne'; doc.save(callback); )
因此要么通过 mongooseAPI 采用上述方式,它可以触发中间件(如 desoares 答案中的“pre”)或触发您自己的验证器,例如:
const theOneAndOnlyName = 'Master Splinter';
const UserSchema = new mongoose.Schema(
username:
type: String,
required: true,
default: theOneAndOnlyName
validate:
validator: value =>
if(value != theOneAndOnlyName)
return Promise.reject('PATH do not specify this field, it will be set automatically');
// message can be checked at error.errors['username'].reason
return true;
,
message: 'PATH do not specify this field, it will be set automatically'
);
或始终使用 runValidators: true
形式的附加“选项”参数调用任何更新函数(例如“findByIdAndUpdate”和朋友),例如:
const splinter = new User( username: undefined );
User.findByIdAndUpdate(splinter._id, username: 'Shredder' , runValidators: true )
.then(() => User.findById(splinter._id))
.then(user =>
assert(user.username === 'Shredder');
done();
)
.catch(error => console.log(error.errors['username'].reason));
您还可以以非标准方式使用验证器功能,即:
...
validator: function(value)
if(value != theOneAndOnlyName)
this.username = theOneAndOnlyName;
return true;
...
这不会抛出“ValidationError”,而是悄悄地覆盖指定的值。它仍然只在使用 save()
或使用指定的验证选项参数更新函数时这样做。
【讨论】:
【参考方案5】:您可以使用Mongoose Immutable。这是一个小包,您可以使用以下命令安装,它允许您使用“不可变”属性。
npm install mongoose-immutable --save
然后使用它:
var userSchema = new mongoose.Schema(
username:
type: String,
required: true,
immutable: true
);
userSchema.plugin(immutablePlugin);
【讨论】:
以上是关于使用 Mongoose Schema 防止字段修改的主要内容,如果未能解决你的问题,请参考以下文章
使用 TypeScript 在 mongoose.Schema 的 `required` 字段中使用函数
访问 mongoose.Schema.methods 中的“select: false”字段
使用 mongoose 在 mongodb 中保存多个字段数组
Typescript Mongoose 在 VS Code 中获取 Schema 字段的 IntelliSense 或警告