Update only in fields that have content other than null - Node with Mongoose

Asked

Viewed 130 times

0

I have a question about giving update using Mongoose. I already have the route done and working, only I’m having a problem.

Rota update usando mongoose

So I’ve unstructured all the data I’m going to take from req.body, then when I pass all the data already filled to do update, goes normal, only in case I passed some data null, it replaces the field by null.

After researching the doc of Mongoose, I found the option omitUndefined, excluding fields undefined of update, only usually when we pass him blank he comes null and not undefined.

Taking the two images below as an example, passing and not passing the blank field.

inserir a descrição da imagem aqui

Passing the name and desc, and replacing normal

inserir a descrição da imagem aqui

Now moving on to desc as null, and within the database overwriting the content by null. And as you can see, the price and the status remain the same, because as they do not pass in the req.body, they come as undefined.

Could someone give me a hand?

Solution found

After receiving help in the post answers, I was able to solve the problem with the solution below using Mongoose

async update(req: Request, res: Response) {
try {
  const { id } = req.params;
  const { name, description, price, status, category } = req.body;

  await product.find(
    { _id: id },
    async function (err, [data]: IProductProps[]) {
      if (!err) {
        const response = await product.findByIdAndUpdate(
          { _id: id },
          {
            $set: {
              name: name || data.name,
              description: description || data.description,
              price: price || data.price,
              status: status || data.status,
              category: category || data.category,
            },
          },
          {
            new: true,
          }
        );

        return res.json(response);
      }
    }
  );
} catch {
  return res.status(400).json({ error: "error for updating a product" });
}

},

  • 1

    Got a little confused! You don’t want to save data null in the bank, is that it? If it is that, it would not be better to define in the model that such a field does not accept null? And from what you wrote, you understand ""(empty string) like null?

  • Thanks for the answer, that, I do not want to save null in mongodb, I searched and does not have a property for example noNullable, there is a required property that makes it mandatory. But even with this property it accepts null in the fields.

1 answer

1


One way to solve the problem is to use the function find before updating the data.

The find function will give you the values that are already filled in for the item you want to update.

These values will be used as default values when the values filled in by req.body are not completed.

A version using async-await

exports.updateUserbyId = async (req, res) => {
    const options = { returnOriginal: false };
    const dbInstance = db.get()
    try {
        const fallbackDataObj = await dbInstance.collection('user').findOne({ _id: new ObjectId(req.params.id) })
        if (fallbackDataObj === null) {
            res.status(404).json({ errors: [{location: "users", msg: "Not found", param: req.params.id}]})
            return
        }
        const result = await dbInstance.collection('user').findOneAndUpdate({_id: ObjectId(req.params.id)}, {$set: {"name": req.body.name || fallbackDataObj.name }}, options)
        if (result.value === null) {
            res.status(404).json({ errors: [{location: "users", msg: "Not found", param: req.params.id}]})
            return
        }
        res.status(200).json(result.value);
    } catch (err) {
        res.status(500).json({errors: [{location: "users", msg: err, param: req.params.id}]})
    }   
}

A version using Promises

Follow an example:

exports.updateUserbyId = (req, res) => {
  db.get().collection('user').findOne({ _id: new ObjectId(req.params.id) }).then((result) => {
    if (result === null) {
        return res.status(404).json({ errors: [{location: "users", msg: "Not found", param: req.params.id}]})
    }
    const options = { returnOriginal: false };
    db.get().collection('user').findOneAndUpdate({_id: ObjectId(req.params.id)}, {$set: {"name": req.body.name || result.name }}, options).then((result1) => {
      if (result1.value === null) {
        return res.status(404).json({ errors: [{location: "users", msg: "Not found", param: req.params.id}]})
      }
      res.status(200).json(result1.value);
      }).catch((err) => {
        res.status(500).json({errors: [{location: "users", msg: err, param: req.params.id}]})
      })
    }).catch((err) => {
        res.status(500).json({ errors: [{location: "users", msg: err, param: req.params}]})
    })
}

The idea is to perform the function find before performing the function findOneAndUpdate.

Pay attention to how the function is implemented $set because that’s where we’re using the values found in find to not save values null at the bank.

The above examples are using lib mongodb

In my implementation I am not using Mongoose so you will have to adapt the code.

  • Thanks for the answer, I will try to adapt to my code using Mongoose to see if it works, so basically we search for the specific user, and with the result we kind of if it is not given in req.body, it will keep the same name as before, it makes sense hehe. Thank you very much

  • 1

    @kissinger156 had the opportunity to improve the code and set an example using async-await.

  • I tried using Dani Mongoose but without success, I did the search with findOne, and in the findByIdAndUpdate, but he did not update hehe, I will try in other ways, thank you very much

  • I was able to use yours as a base and it worked Dani, I updated with the solution, thank you really!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.