oussama ghrib
oussama ghrib

Reputation: 99

findByIdAndUpdate result in an "validation failed" error when i set "runValidators" to "true"

i have an express app with a put request that updates a phonebook if i found that the person's name already exists in this phone book (i'm using the "mongoose-unique-validator" that have the unique: true option in validation)

but i have the problem with this put request only when i set findByIdAndUpdate's runValidators to true

here is my code
the schema

const personSchema = new mongoose.Schema({
  name: { type: String, required: true, minlength: 3, unique: true },
  number: {
    type: String,
    required: true,
    validate: {
      validator: function (str) {
        //the function to validate the number
      },
      message: "phone number must contain at least 8 digits",
    },
  },
});
personSchema.plugin(uniqueValidator);
personSchema.set("toJSON", {
  transform: (document, returnedObject) => {
    returnedObject.id = returnedObject._id.toString();
    delete returnedObject._id;
    delete returnedObject.__v;
  },
});
const Person = mongoose.model("Person", personSchema);

the put request

app.put("/api/persons/:id", (req, res, next) => {
  const id = req.params.id;
  console.log(id);
  const body = req.body;
  const person = {
    name: body.name,
    number: body.number,
  };
// opts is supposed to be true; and this is where i have the problem
  const opts = { runValidators: false };
  Person.findByIdAndUpdate(id, person, opts)
    .then((updatedPerson) => {
      res.json(updatedPerson);
    })
    .catch((error) => next(error));
});

the error handler

const errorHandler = (error, req, res, next) => {
  console.error(error.message);

  if (error.name === "CastError" && error.kind == "ObjectId") {
    return res.status(400).send({ error: "malformatted id" });
  } else if (error.name === "ValidationError") {
    return res.status(400).json({ error: error.message });
  }

  next(error);
};

app.use(errorHandler);

the error i'm getting is

error: "Validation failed: name: Cannot read property 'ownerDocument' of null"

Upvotes: 1

Views: 1035

Answers (2)

Jesse Moskowitz
Jesse Moskowitz

Reputation: 31

@oussama ghrib If you're not updating the name and you're only updating the number (as you indicated), the update object can just have the phone number, like below:


    app.put('/api/persons/:id', (req, res, next) => {
      const { number } = req.body
      Person.findByIdAndUpdate(req.params.id, { number }, {
        new: true,
        runValidators: true,
        context: 'query'
      })
        .then((updatedPeep) => {
          res.json(updatedPeep)
        })
        .catch((err) => next(err))
    })

If you're using runValidators: true you also need context: 'query' as explained here: https://github.com/blakehaswell/mongoose-unique-validator#find--updates findOneAndUpdate works like findByIdAndUpdate for this purpose.

Upvotes: 3

Sehroz Khan
Sehroz Khan

Reputation: 18

The issue is with your usage of: findByIdAndUpdate(id, update, opts)

The update object should be properties you want to update otherwise it will also to try update the id.

Solution:

app.put("/api/persons/:id", (req, res, next) => {
         const { name, number } = req.body;
        
         Person.findByIdAndUpdate(req.params.id, { name, number }, opts )
            .then((updatedPerson) => {
              res.json(updatedPerson);
            })
            .catch((err) => next(err));
    }

https://mongoosejs.com/docs/api/model.html#model_Model.findByIdAndUpdate

Upvotes: 0

Related Questions