当MongoDB中至少需要一个子文档时,有什么更好的方法可以防止删除所有子文档



采用mongoose中定义的一个简单模式,如下所示:

const Person = new Schema({
username: {
type: String,
index: true,
},
roles: [{
type: Schema.Types.ObjectId,
ref: 'Role',
required: [true,
'Role is required'],
}],
})

当您在不提供至少一个角色的情况下保存新记录时,MongoDB将抛出一个需要角色的错误。

我有另一段代码,您可以在其中更新(添加或删除(角色数组中的角色。但是,我可以使用下面的代码段删除所有角色。

Person.findOneAndUpdate({_id: 'some id'}, {
$pull: {
roles: {
$in: [...list of ids,]
}
}
}, {new: true}).populate('roles').exec()

假设我列出了那个人的所有角色,我会删除它们,让那个人没有角色。

我如何强制执行早先的要求,即角色是必需的?有没有一个简单的破解,或者我应该写一段代码来验证这个删除并自己强制执行?

之所以能够删除所有角色,并且所需的验证不起作用,是因为验证是作为Mongoose中的内部中间件实现的,中间件在更新过程中不会执行。你可以在这里阅读更多关于它的信息。

如果使用MongoDB 4.0或更高版本,则可以在update调用中使用runValidators: true选项。您可以在Mongoose更新验证器文档中阅读更多关于runValidators选项的信息。

你可以试试下面的代码(我还没有测试过(:

Person.findOneAndUpdate({_id: 'some id'}, {
$pull: {
roles: {
$in: [...list of ids,]
}
}
}, {new: true, runValidators: true}).populate('roles').exec()

根据Mongoose官方文档,更新验证器的工作以下运营商(以及MongoDB versoins(:

  • $set
  • $unset
  • $push(>=4.8.0(
  • $addToSet(>=4.8.0(
  • $pull(>=4.12.0(
  • $pullAll(>=4.12.0(

或者您还可以为findOneAndUpdate、设置Pre挂钩

// Pre hook for `findOneAndUpdate`
ClientSchema.pre('findOneAndUpdate', function(next) {
this.options.runValidators = true;
next();
});

如果您有MongoDB<4.0

然后,您可以使用.findOne()查找文档,在文档中设置新属性,然后尝试使用.save()再次保存它。这应该运行验证。

最新更新