Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Patch Request Method in Node.js and Mongoose

For update I use the following code that works:

router.put('/:id', async (req, res) => {
  const { error } = validateProduct(req.body); 
  if (error) return res.status(400).send(error.details[0].message);

  const product = await Product.findByIdAndUpdate(req.params.id, 
    { 
     name: req.body.name,
     description: req.body.description,
     category: req.body.category,
     tags: req.body.tags,
     withdrawn: req.body.withdrawn,
     extraData: {
       brand: req.body.extraData.brand,
       quantity: req.body.extraData.quantity,
       type: req.body.extraData.type
     } 
   }, 
   {new: true}
  );

  if (!product) return res.status(404).send('The product with the given ID was not found.');

  res.send(product);
});

What I want to do is to create a Patch operation that updates only certain fields and not all of them as the update above. These fields are not standard but they are one of the above fields of the update operation.

like image 715
Giannis Avatar asked Nov 01 '25 19:11

Giannis


1 Answers

You can try this snippet (didn't test it locally though). The idea is to only update those fields in Product, which were mentioned in req.body. Be sure your validator is secure, otherwise you can end up with nosql injection.

router.put('/:id', async (req, res) => {
  const { error } = validateProduct(req.body); 
  if (error) return res.status(400).send(error.details[0].message);

  const product = await Product.findById(req.params.id).exec();
  if (!product) return res.status(404).send('The product with the given ID was not found.');

  let query = {$set: {}};
  for (let key in req.body) {
    if (product[key] && product[key] !== req.body[key]) // if the field we have in req.body exists, we're gonna update it
       query.$set[key] = req.body[key];

  const updatedProduct = await Product.updateOne({_id: req.params.id}, query}).exec();

  res.send(product);
});

Also I'm sure you can leverage lodash in the line, where I you use a for-in loop ;)

The downside of this approach is that it takes 2 queries to mongo, because you need a real document to compare the thing. Also update operation doesn't trigger post save hooks of your model. If you need them - you should findById() first, update necessary fields and then hit .save() on the very document you found. Hope it helps

like image 191
Vladyslav Usenko Avatar answered Nov 04 '25 11:11

Vladyslav Usenko