1

So the issue that I'm having is that I want to like user comment only one time, currently im using addToSet operator, since by definition it doesn't add value if that value is already present.

But in my case it adds, probably because I am adding object instead of value and when I add mongo generates _id?

This is my event model:

  creator: {
    type: Schema.Types.ObjectId,
    ref: 'User'
  },
  comments: [
    {
      user: {
        type: Schema.Types.ObjectId,
        ref: 'User'
      },
      text: {
        type: String,
        required: true
      },
      likes: [
        {
          user: {
            type: Schema.Types.ObjectId,
            ref: 'User'
          }
        }
      ]
    }
  ]
}

And this is my addLike function:

commentLike: async (req, res) => {
    console.log('working', req.params.id, req.params.idas, req.params.commentID);
    Events.findOneAndUpdate(
      { _id: req.params.idas, comments: { $elemMatch: { _id: req.params.commentID } } },
      { $addToSet: { 'comments.$.likes': { user: req.params.id } } },
      (result) => {
        res.json(result);
      }
    );
  }

My likes array looks like this when I add like:

        "likes" : [
            {
                "user" : ObjectId("5b53442c1f09f525441dac31"), 
                "_id" : ObjectId("5b54a5263e65324504035eac")
            }, 
            {
                "user" : ObjectId("5b4b4725a3a5583ba8f8d513"), 
                "_id" : ObjectId("5b54a5bb3e65324504035eb0")
            },
          ]
Tautvydas Būda
  • 188
  • 1
  • 4
  • 17
  • It will not work because `$addToSet` takes whole object in a context and here you are adding with respect to `user` only... So here your one element is `{ "user" : ObjectId("5b53442c1f09f525441dac31"), "_id" : ObjectId("5b54a5263e65324504035eac") }` now it will add if there will be same `user` but with different `_id` but if your both `user` and `_id` will be same then it will not be added.. – Ashh Jul 22 '18 at 16:45
  • I see, so are there any other ways to wont let user add to array even if _id's will differ? – Tautvydas Būda Jul 22 '18 at 16:49
  • Possible duplicate of [Can you specify a key for $addToSet in Mongo?](https://stackoverflow.com/questions/14527980/can-you-specify-a-key-for-addtoset-in-mongo) – Ashh Jul 22 '18 at 16:50
  • 1
    Would be better to make `likes` an array of user ObjectIds instead of objects. That would reduce the doc size and allow `$addToSet` to work as you intend. – JohnnyHK Jul 22 '18 at 17:26

2 Answers2

2

You can follow this

db.collection.update(
  { "_id": req.params.idas, "comments": { "$elemMatch": { "_id": req.params.commentID, "likes.user": { "$ne": req.params.id } } } }, 
  { "$push": { "comments.$.likes": { "user": req.params.id } } }
})

And if you just started with your project then you should follow JohnnyHK opinion and make your array some thing like this to make $addToSet workable

likes: [{ type: Schema.Types.ObjectId, ref: 'User' }]
Ashh
  • 44,693
  • 14
  • 105
  • 132
1

Another option is to change your schema definition to add "_id: false" to prevent the _id field from being generated for subdocs in the array.

In this case, $addToSet will work as you expect, even with nested subdocs as long as your doc exactly matches.

comments: [
    {
      user: {
        type: Schema.Types.ObjectId,
        ref: 'User'
      },
      text: {
        type: String,
        required: true
      },
      likes: [
        {
          _id: false, //add this
          user: {
            type: Schema.Types.ObjectId,
            ref: 'User'
          }
        }
      ]
    }
  ]
Clayton Gulick
  • 9,755
  • 2
  • 36
  • 26