2

Hi I'm new to mongodb and node.js. I have the following abbreviated schema:

const PostSchema = new Schema({
  user: {
    type: Schema.Types.ObjectId,
    ref: 'user'
  },
  likes: [
    {
      user: {
        type: Schema.Types.ObjectId,
        ref: 'user'
      }
    }
  ],...

I want to access each Post by id (passed through request params) and then remove a like based on the user id. Presently, it removes the like from the array but does not then throw any errors when I try again to remove the same id from the db. Here is my code at the moment:

const like = await Post.findByIdAndUpdate(
      req.params.id,
      { $pull: { likes: { user: req.user.id } } },
      (error, result) => {
        if (!error) {
          return res.json('Post unliked');
        }
        return res.status(400).send('You have not liked this post');
      }
    );

3 Answers3

1

Find the correct post with findById() instead of findByIdAndUpdate and use the higher order function map() to access the specific index of the like with the required user property.

await Post.findById(req.params.id, async (error, result) => {
      if (!error) {
        const index = result.likes
          .map(like => {
            return like.user;
          })
          .indexOf(req.user.id);

        if (index > -1) {
          console.log('found');
          //was found
          result.likes.splice(index, 1);
          await result.save();
          return res.json('Post unliked');
        } else {
          console.log('not found');
          return res.status(400).send('You have not liked this post');
        }
      }
      return res.json(error);
    });
0

If the Id doesn't exist's then it return null so you can check if it return null then you can send the response with status 400 else you can send response with status 200. I think this can be the solution to your problem hope it work, thanks!

0

Try something like this, and please let me know if it works:

 await Post.findByIdAndUpdate(
      req.params.id, (error, result) => {
        if (!error) {//if error
          return res.json(error);
        }

         const index = result.likes.indexOf(`${req.user.id}` )//find the index, I am not sure if you will need to add it as a string, make some tests!   

     if (index > -1) {//was found
       result.likes.splice(index, 1);//remove
       result.save();//save the doc to mongo
       return res.json('Post unliked');

        } 
      else  return res.status(400).send('You have not liked this post');// it was not found
      }
    );

You may need to adjust something since I am writing the code from my head!

I hope that helps!

References:

  1. How can I remove a specific item from an array?
  2. https://www.w3schools.com/jsref/jsref_indexof.asp
  3. Mongoose indexOf in an ObjectId array <- this one explains that indexof do work for mongoose ids!
  • 1
    Thanks Jorge, will try this tomorrow and let you know. – Finnan Holt Apr 07 '20 at 22:38
  • 1
    Hi Jorge, this response led me to the correct answer. I had to use findById() instead of findByIdAndUpdate and I had to use the higher order function map() to access the specific index of the like with the correct user property. I'm going to update this post with the correct answer. Thanks again for your help. – Finnan Holt Apr 08 '20 at 19:07
  • Okay, glad to help! – Jorge Guerra Pires Apr 08 '20 at 19:20