简体   繁体   中英

Removing the sub-document from the array by id and curent user restriction

I've got a Messages collection with objects like this:

{
    "_id": ...,
    "author": 123,
    "body": "merp",
    "comments": [
        {
            "_id": ...,
            "author": 234,
            "body": "But what about morp?"
        },
        {
            "_id": ...,
            "author": 123,
            "body": "You're out of your element, Donnie!"
        }
    ]
}

I'm creating those comment._id s myself when adding them. Anyway, everything works fine, I found out how to add and delete stuff from the comments array etc.

Except now when deleting a comment, I want to check first if the author is the current user. In Meteor, usually you pass the object id to a Meteor-method, which then checks the object and decides whether it's ok to execute. Eg to delete a message, my method looks like this:

Meteor.methods({
  deleteMessage: function(messageId) {
    message = Messages.findOne(messageId);

    if(!message) {
      throw new Meteor.Error("not-found");
    }
    if(Meteor.userId() != message.author) {
      throw new Meteor.Error("not-authorized");
    }

    Messages.remove(messageId);
  }
});

Now how would I do the same for comment objects? I suppose I will have to pass both messageId and commentId , which is not a problem, but then how do I do the permission check? I can't just get a single comment object by _id , can I? At least I've been trying to google this but failed. Should I first retrieve the message object, then manually look through it's comments array to find the one with the correct _id ?

So to make this more clear : I know how to use $pull to delete comment objects by _id , what I'm looking for is how do I check whether the object exists in the first place, and that its author is the current user?

Disclaimer : I'm new to Mongo and am fighting the urge to put the comment objects in its own collection, relational-style. From what I've read you're supposed to put everything into one big document. It could well be that I'm missing a crucial point here and in case you see it please point it out to me, even if it does not answer the original question. Thanks! :)

To remove an item from the array then you want to use the $pull operator with .update()

Messages.update(
   { 
       "_id": messageId, 
       "comments._id": commentId,
       "comments.author": Meteor.userId()
   },
   { "$pull": { "comments": { "_id": commentId } } }
)

Optionally look for the presence of the "comments._id" as well in the query statement to avoid a match if that comment has already been removed by another request.

To clarify the "method inside the query argument", this is JavaScript, so any function() is evaluated into the object sytax with it's returned value. So before the .update() is executed the Meteor.userId() value is commited with it's return value.

The $pull operator works like a query condition in itself, and will remove any elements matching the conditions from the array. You could also include the same "author" check in there, but it's not really necessary.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM