Ramsay Lanier
Ramsay Lanier

Reputation: 426

Meteor: Remove collection attributes when another collection is deleted

I have two collections: one for Posts and one for Categories. Posts have one or more categories. I'd like for the Posts collection to be updated if a category is deleted, so that posts do contain any non-existent categories. I've got this to work, but I'm not sure it is the most efficient way to do it.

This code is what fires when a category delete button is pressed. This both removes the category from the collection, and goes through each post that contains the category and updates the category array to exclude the deleted category.

Template.listCategories.events({
    'click .delete-category': function(e){
        e.preventDefault();
        var category = this.name;
        Categories.remove(this._id);

        var posts = Posts.find({categories: category}).fetch();
        for (var i=0;i<posts.length;i++){
            var cats = _.without(posts[i].categories, category);
            Posts.update(posts[i]._id, {$set: {categories: cats}});
        }       
    }
});

First I set the a 'category' variable to equal the name of the category being deleted. Second, I actually remove the category from the collection.

Lastly, I set a 'posts' variable equal to a fetch of all posts that contain the category name, which returns an object of posts. I iterate through the posts, and, with the help of underscore, I use the '_.without' function to return an array of categories that excludes the deleted category. I then call Posts.update to update the categories with the new array.

My concern, though, is that I'm calling Posts.update each time in the For loop. It's a client side call, so maybe that doesn't matter as much? I still feel like there is a better way to do this. Any help?

Upvotes: 1

Views: 211

Answers (1)

Tobias
Tobias

Reputation: 4074

I think you are looking for the $pull operator (docs):

The $pull operator removes all instances of a value from an existing array.

With this your code can be simplified to this:

Template.listCategories.events({
    'click .delete-category': function(e){
        e.preventDefault();
        var category = this.name;
        Categories.remove(this._id);

        Posts.update({categories: category}, {$pull: {categories: category}}, {multi:true});     
    }
});

NB:

It's a client side call, so maybe that doesn't matter as much?

Your assertion is wrong, Posts.update is not just a client-side call. Actually, a stub that using minimongo simulates the effect of the update operation is executed on the client while in parallel the update is also remotely executed on the server.

Upvotes: 1

Related Questions