0

In a node.js server based on express, interacting with a mongo db through mongoose, I would like to insert a 'review' on 'reviews' array only if the user(identified by his id) hasn't reviewed the product yet, otherwise, update the review previously inserted. Given the following mongo schemes:

Product:

var ProductSchema = new Schema({
  ownerId: {
    type: Schema.ObjectId,
    required: 'Owner of recharge point required'
  },
  name: {
    type: String,
    required: 'The name is required'
  },      
  description: {
    type: String
  },
  reviews: {
    type: [Review]
  }
});

Review:

  var ReviewSchema = new Schema({
  reviewerId: {
    type: ObjectId,
    required: 'Reviewer id required',
    ref: 'User' <not showed>
  },
  review: {
    type: String
  },
  date: {
    type: Date, 
    default: Date.now
  }
});

That's the result I came up with, but this only insert new reviews, it doesn't update them yet. I think my solution could be improved (and simplified) a lot.

exports.review_product = function (req, res) {
    const review = req.body.review;
    const reviewerId = req.body.reviewerId;
    const productId = req.params.productId;

    Product.findOne({_id: productId}, function(error, result){
          if(error) {
               res.status(500).send({message: error}).end()
           } else if(result){
               var newReview = new Review({ reviewerId: reviewerId, review: review});
               Product.findOneAndUpdate({ _id: productId, 'reviews.reviewerId': { $ne: reviewerId }}, 
                 { $push: { 'reviews': newReview}},
                 function(error, found) {
                     if (error) {
                        res.status(500).send({message: error}).end()
                     } else if(found) {
                        res.status(200).send({message: 'Review succefully added.'}).end()
                     } else {
                        res.status(404).send({message: 'You already reviewed this product'}).end()
                     }
              });
           } else {
               res.status(404).send({message: 'Cannot find the product to be reviewed.'}).end()
           }
  })
};

2 Answers 2

1

The best approach would be make a query with mongoose to check the product for the reviewer id before anything else. You can also make your code a bit more readable using async/await.

It would likely look something like (please note this is pseudo code):

exports.reviewProduct = async (req, res) => {
    const review = req.body.review;
    const reviewerId = req.body.reviewerId;
    const productId = req.params.productId;

    const hasReviewed = await Product.find({_id: productId, 'reviews.reviewerId': { $eq: reviewerId } )

    if(hasReviewed) {
        Product.findOneAndUpdate({
            _id: productId, 
            reviews: { $elemMatch: { reviewerId: reviewerId } }
            },
            { $set: {
                'review.$.title': review.title,
                'review.$.body': review.body
             }},
             {'new': true, 'safe': true, 'upsert': true})
    } else {
        Product.findOneAndUpdate(
            { _id: productId }, 
            { $push: { reviews: review } },
            {safe: true, upsert: true, new : true},
            (err, model) => {
               console.log(err);
            })
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

You can use the function includes()

For example:

var array = ["a","b","c"];
console.log(array.includes("a"); //return true
console.log(array.includes("z"); //return false because is not exist

Just adapt it to your code by replacing the variable string by your object

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.