70

我有这个代码

var ClientSchema = new Schema({
  name: {type: String, required: true, trim: true}
});

var Client = mongoose.model('Client', ClientSchema);

使用 express,我用这段代码创建了一个新客户端

var client = new Client(req.body);
client.save(function(err, data) {
  ....
});

如果我将表单上的名称字段留空,则猫鼬不允许创建客户端,因为我在架构上根据需要设置了它。此外,如果我在名称前后留有空格,猫鼬会在保存之前删除该空格。

现在,我尝试使用此代码更新客户端

var id = req.params.id;
var client = req.body;
Client.update({_id: id}, client, function(err) {
  ....
});

它让我可以更改名称,但如果我在表单上将其留空,猫鼬不会验证并保存一个空名称。如果我在名称前后添加空格,则会用空格保存名称。

为什么猫鼬在保存时验证而不是在更新时验证?我做错了?

mongodb:2.4.0 猫鼬:3.6.0 express:3.1.0 节点:0.10.1

4

7 回答 7

100

从 Mongoose 4.0 开始,您可以在新标志上运行验证器update()使用它。findOneAndUpdate()runValidators: true

Mongoose 4.0 引入了一个选项来运行验证器update()findOneAndUpdate()调用。update()打开此选项将为您的调用尝试的所有字段运行验证器$set$unset.

例如,给定 OP 的 Schema:

const ClientSchema = new Schema({
  name: {type: String, required: true, trim: true}
});

const Client = mongoose.model('Client', ClientSchema);

在每次更新时传递标志

您可以像这样使用新标志:

const id = req.params.id;
const client = req.body;
Client.update({_id: id}, client, { runValidators: true }, function(err) {
  ....
});

pre在钩子上使用标志

如果您不想在每次更新某些内容时设置标志,您可以设置一个pre钩子findOneAndUpdate()

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

然后,您可以update()使用验证器而无需runValidators 每次都传递标志。

于 2015-04-05T17:20:32.543 回答
75

您没有做错任何事情,validation它是作为 Mongoose 中的内部中间件实现的,并且中间件不会在运行期间执行,update因为这基本上是对本机驱动程序的传递。

如果您希望验证您的客户端更新,您需要find更新对象,将新的属性值应用到它(参见下划线的extend方法),然后调用save它。

猫鼬 4.0 更新

如评论和 victorkohl 的回答中所述,当您在调用中包含选项时,Mongoose 现在支持验证$set和运算符的字段。$unsetrunValidators: trueupdate

于 2013-03-26T04:38:50.683 回答
12

默认情况下,MongoDB 不会对更新进行验证。

为了在更新发生时默认进行验证,就在连接到 MongoDB 之前,您可以只设置全局设置,如下所示:

mongoose.set('runValidators', true); // here is your global setting

mongoose.connect(config.database, { useNewUrlParser: true });
mongoose.connection.once('open', () => {
    console.log('Connection has been made, start making fireworks...');
}).on('error', function (error) {
    console.log('Connection error:', error);
});

因此,任何内置或自定义验证也将在任何更新上运行

于 2018-12-19T17:13:09.747 回答
1

您可以通过设置选项在更新时运行验证runValidators: true

示例 1:


const Kitten = db.model('Kitten', kittenSchema);

const update = { color: 'blue' };
const opts = { runValidators: true };
Kitten.updateOne({}, update, opts, function() {
  // code
});

示例 2:

const Kitten = db.model('Kitten', kittenSchema);

const update = { color: 'blue' };
const opts = { runValidators: true };
Kitten.updateOne(
  {
    _id: req.params.id
  },
  {
    $set: { ...update },
  },
  opts
).then(result => {
    // code
})

阅读更多:https ://mongoosejs.com/docs/validation.html#update-validators

于 2021-04-16T18:48:11.260 回答
1

如果您在 mongoose 的配置中添加此选项,它将起作用:

mongoose.set('runValidators', true)
于 2020-10-13T01:42:20.020 回答
1

upsert如果您在findOneAndUpdate选项中使用,接受的答案将不起作用。解决此问题的方法是创建一个模型静态方法,该方法执行findOne然后updateOnecreate在引擎盖下。create自动运行验证。

export async function findOneAndUpdateWithValidation(
  this: LocationModel,
  filter: FilterQuery<LocationDocument>,
  update: UpdateQuery<LocationDocument>,
  options?: QueryOptions
) {
  const documentFound = await this.findOne(filter);
  
  if (!documentFound) return this.create(update);

  return this.updateOne(filter, update, options);
}

locationSchema.statics = {
  findOneAndUpdateWithValidation
}
于 2021-09-27T13:35:38.707 回答
-1

在您的模型中,例如。Category.js 文件:

const CategorySchema = mongoose.Schema({
category_name : {
type : String,
required : [true, 'Category Name Is Required !'],
trim : true,
maxlength : [30, 'Category Name Is To Long !'],
unique : true,
});
const Category = module.exports = mongoose.model("Category",CategorySchema);

在您的路线文件中:

router.put("/",(req,res,next)=>{
  Category.findOneAndUpdate(
  {_id : req.body.categoryId},
  {$set : {category_name : req.body.category_name} },
  **{runValidators: true}**, function(err,result) {
    if(err){
      if(err.code === 11000){
       var duplicateValue = err.message.match(/".*"/);
       res.status(200).json({"defaultError":duplicateValue[0]+" Is Already Exsist !"});
       }else{
         res.status(200).json({"error":err.message} || {"defaultError":'Error But Not Understood !'});
       }
    }else{
     console.log("From category.js (Route File) = "+result);
     res.status(200).json({"success":"Category Updated Successfully!!"});
    }
});
于 2018-05-04T10:52:28.813 回答