在创建Schema时应用了Validations,设置了required、minlength、unique等等限制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const personSchema = new mongoose.Schema({ name: { type: String , required: [true , 'The name is required' ], unique: true , minlength: [3 , 'The name has to be at least three characters long' ] }, number: { type: String , required: [true , 'The phone number is required' ], minlength: [8 , 'The phone number must have at least 8 digits' ] } }) personSchema.plugin(uniqueValidator)
在POST请求也就是创建新联系人的时候的确有用(大概是用了save()的缘故?)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 app.post('/api/persons' , (req, res, next ) => { const body = req.body console .log(body) const person = new Person({ name: body.name, number: body.number, }) console .log(person) person.**save()** .then(savedPerson => { console .log(savedPerson) return savedPerson.toJSON() }) .then(savedAndFormattedPerson => { res.json(savedAndFormattedPerson) }) .catch(error => next(error)) })
但如果要修改(PUT请求)联系人信息,Validations就无法生效了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 app.put('/api/persons/:id' , (req, res, next ) => { const body = req.body const person = { name: body.name, number: body.number, } Person.findByIdAndUpdate(req.params.id, person, {new : true }) .then(updatedPerson => { if (updatedPerson) { res.json(updatedPerson) } else { res.status(404 ).end() } }) .catch(error => next(error)) })
查了Mongoose文档:
runValidators: if true, runs update validators on this command. Update validators validate the update operation against the model’s schema.
Mongoose v6.0.6:
以及相关问答:
Mongoose findByIdAndUpdate not running validations on subdocuments
According to the documentation, validators seems to work only for update() and findOneAndUpdate() if runValidators is set to true.
但其实文档里也说过findByAndUpdate也可以支持有限的validation的。。。(可能这个回答时间比较久远了,现在好像是可行的)
见下:
Note: findOneAndX
and findByIdAndX
functions support limited validation that you can enable by setting the runValidators
option.
If you need full-fledged validation, use the traditional approach of first retrieving the document.
1 2 3 const doc = await Model.findById(id);doc.name = 'jason bourne' ; await doc.save();
按照文档试了一下好像确实可以
修改后的PUT代码部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 app.put('/api/persons/:id' , (req, res, next ) => { const body = req.body const person = { name: body.name, number: body.number, } Person.findByIdAndUpdate(req.params.id, person, **{new : true , runValidators : true }**) .then(updatedPerson => { if (updatedPerson) { res.json(updatedPerson) } else { res.status(404 ).end() } }) .catch(error => next(error)) })
前端也作了修改,加了if-else判断error的类型后再输出报错的message,也不知道在异步方法下加判断会不会有坑,但功能上是实现了的。相关代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 personService .update(samePerson.id, changedPerson) .then(returnedPerson => { console .log(returnedPerson) setPersons(persons.map(person => person.id === samePerson.id ? returnedPerson : person)) setNewName('' ) setNewNumber('' ) setError(false ) setMessage( `Updated ${returnedPerson.name} 's number` ) setTimeout (() => { setMessage(null ) }, 5000 ) }) .catch(error => { console .log(error.response.data.error) **if (error.response.data.error) { setMessage( `${error.response.data.error} ` ) setTimeout (() => { setMessage(null ) }, 5000 ) setError(true ) setNewName('' ) setNewNumber('' ) } else { setMessage( `Information of ${samePerson.name} has already been removed from server` ) setTimeout (() => { setMessage(null ) }, 5000 ); setPersons(persons.filter(person => person.name !== newName)) setNewName('' ) setNewNumber('' ) setError(true ) }** })
降低冗余后:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 const samePerson = persons.find(person => person.name === newName) const changedPerson = { ...samePerson, number : newNumber } personService .update(samePerson.id, changedPerson) .then(returnedPerson => { console .log(returnedPerson) setPersons(persons.map(person => person.id === samePerson.id ? returnedPerson : person)) setNewName('' ) setNewNumber('' ) setError(false ) setMessage( `Updated ${returnedPerson.name} 's number` ) setTimeout (() => { setMessage(null ) }, 5000 ) }) .catch(error => { **if (error.response.data.error) { setMessage( `${error.response.data.error} ` ) } else { setMessage( `Information of ${samePerson.name} has already been removed from server` ) setPersons(persons.filter(person => person.name !== newName)) } setTimeout (() => { setMessage(null ) }, 5000 ) setError(true ) setNewName('' ) setNewNumber('' )** })