Returning a collection list filtered from an array

One thing I was trying to figure out lately is if it was possible to filter a collection from an array of id’s. Imagine you got a task model that lists another sub-task model. In your task model you got an array of sub-tasks, [1,4,7]. How would you go to retrieve those models?

The loop

The easiest way of doing this is by looping the array and saving the models one by one in a new collection.The code in your view would look like something like this:

var currentSubtask = new SubtaskCollection;
_.each(this.model.toJSON().subtasksArray, function(taskID){
	var mySubTask = allSubTasks.getOne(taskID)
	currentSubtask.add(mySubTask)
})

When we are about to show the sub-tasks for a master task, we loop our sub-tasks array and retrieve the sub-tasks one by one.

In our sub-tasks collection declaration, we would have this filter:

	getOne : function(SubTaskid){
		return this.filter(function(data) {
		  	return data.get("id") == SubTaskid;
		});
	},

Easy, we get one model each time. Obviously this technique is really not the most efficient. What we really want to achieve is not having to loop through our sub-tasks array on the view side, but directly pitch the array in the collection filter.

A better way

To do this we will have to change our filter, what we will do is check if each model through our collection exists in our sub-tasks array. If its not, its going to return -1 and in that case we are not going to keep it.

	getGuestById : function(subtasksArray){
		return this.select(function(model){
		    return (_.indexOf(subtasksArray, model.get("id")) > -1);
		  });
	}

This will return a list of models that you can add to a collection. We could also return a collection of those models directly wrapping everything with _()

	getGuestById : function(subtasksArray){
		return _(this.select(function(model){
		    return (_.indexOf(subtasksArray, model.get("id")) > -1);
		  }));
	}

That’s it

Here we go for filtering with arrays, in my next article I will use this technique to “bind” 2 models together and handle small relationships.

Cedric Dugas is a front-end veteran with more than 9 years under the belt, between his open source projects & entrepreneurial ambitions he is a product architect at CakeMail. Why don't you follow him on twitter.

2 Comments on "Returning a collection list filtered from an array"

  1. Ondra says:

    If I get it correctly, you have two collections, Tasks and Subtasks, that are tied together via Task atribbute subtasksArray. You could iterate over this array and use collection.get():

    var currentSubtask = new SubtaskCollection;
    _.each(this.model.toJSON().subtasksArray, function(taskID) {
    currentSubtask.add(allSubTasks.get(taskId));
    });

    Also consider having a subtask collection in your Task model…

  2. Johnny says:

    Great post.

    Just an FYI, _.select is now _.filter as of 1.2.1. It took a second for me to figure out why I was getting errors.

Got something to say? Go for it!