i am trying to update a single field of a model using patch but it does not allow me to since in the model I have set some feilds as required

Viewed 24

My Model

const mongoose = require('mongoose')
const validator = require('validator')
// mongoose.connect('mongodb://localhost:27017/task-manager-api')

// creating a schema for the user
const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    trim: true,
  },
  age: {
    type: Number,
    default: 0,
  },
  email: {
    type: String,
    required: true,
    unique: true,
    trim: true,
    validate(value) {
      if (!validator.isEmail(value)) {
        throw new Error('invalid email')
      }
    },
  },
  password: {
    type: String,
    required: true,
    trim: true,
    minLength: 7,
    validate(value) {
      if (value.includes('password')) {
        throw new Error('password cannot be password. I mean come on!')
      }
    },
  },
})

// middleware to hash the password before saving

userSchema.pre('save', async function (next) {
  const user = this
  console.log('from the middle ware you are about to save the user')
  next()
})

const User = mongoose.model('User', userSchema)
module.exports = User

Patch router

router.patch('/users/:id', async (req, res) => {
  // making sure that user can only update the fields that are allowed
  const userSentUpdateKeys = Object.keys(req.body)
  const allowedUpdateFields = ['name', 'age', 'email', 'password']
  const isValidUpdate = userSentUpdateKeys.every((update) =>
    allowedUpdateFields.includes(update)
  )

  if (!isValidUpdate) {
    return res.status(400).send({ error: 'invalid update' })
  }

  try {
    // const user = await User.findByIdAndUpdate(req.params.id, req.body, {
    //   runValidators: true,
    //   new: true,
    // })

    const user = await User.findById(req.params.id)
    allowedUpdateFields.forEach((update) => (user[update] = req.body[update]))
    await user.save()

    !user ? res.status(404).send() : res.status(201).send(user)
  } catch (e) {
    res.status(400).send(e)
  }
})

Response (404) it says I have to provide new values of all the fails but I don't want to

{
    "errors": {
        "password": {
            "name": "ValidatorError",
            "message": "Path `password` is required.",
            "properties": {
                "message": "Path `password` is required.",
                "type": "required",
                "path": "password"
            },
            "kind": "required",
            "path": "password"
        },
        "email": {
            "name": "ValidatorError",
            "message": "Path `email` is required.",
            "properties": {
                "message": "Path `email` is required.",
                "type": "required",
                "path": "email"
            },
            "kind": "required",
            "path": "email"
        }
    },
    "_message": "User validation failed",
    "name": "ValidationError",
    "message": "User validation failed: password: Path `password` is required., email: Path `email` is required."
}

I am making calls to the API. I want all the fields to be required when I create a user but not when updating it. I want to be able to update a single field. please help me. I am using mongoose with node js and express.

1 Answers

Instead of saving a user again, use findByIdAndUpdate function. This method takes 3 parameter.

  1. Id
  2. Date to be update
  3. Options

In 3rd parameter i.e. options, most of the developers add this object

{
  new: true, // returns new updated document
  runValidators: false, // depends whether you want to validate data or not
}
Related