Searching for text inside nested object (Backbone.js collection as example)
backbone.js, full-text-search, javascript, jquery, underscore.js
Solution
Backbone extends a lot of the underscore methods into the `Collection` class so you can get rid of some of that stuff. Really you probably want to impliment this on the collection itself as a method, then I would probably look at those keys using a good old fashioned `for` loop, especially if I wanted to break out of it.
// in Backbone.Collection.extend
search: function( query, callback ){
var pattern = new RegExp( $.trim( query ).replace( / /gi, '|' ), "i");
var collection = this;
collection.each(function(model) {
for( k in model.attributes ){
if( model.attributes.hasOwnProperty(k) && pattern.test(model.attributes[k]) ){
callback.call( collection, model, k );
break; // ends the for loop.
}
}
});
}
// later
collection.search('foo', function( model, attr ){
console.log('found foo in '+model.cid+' attribute '+attr);
});
That said, this would only ever return the first match from the collection. You may prefer an implementation that returns an array of results as [model, attribute] pairs.
// in Backbone.Collection.extend
search: function( query, callback ){
var matches = [];
var pattern = new RegExp( $.trim( query ).replace( / /gi, '|' ), "i");
this.each(function(model) {
for( k in model.attributes ){
if( model.attributes.hasOwnProperty(k) && pattern.test(model.attributes[k]) ){
matches.push([model, k]);
}
}
});
callback.call( this, matches );
}
// later
collection.search('foo', function( matches ){
_.each(matches, function(match){
console.log('found foo in '+match[0].cid+' attribute '+match[1]);
});
});
Or, if you wanted an array of models which matched but don't care which attribute matched you can use `filter`
// in Backbone.Collection.extend
search: function( query, callback ){
var pattern = new RegExp( $.trim( query ).replace( / /gi, '|' ), "i");
callback.call( this, this.filter(function( model ){
for( k in model.attributes ){
if( model.attributes.hasOwnProperty(k) && pattern.test(k) )
return true;
}
}));
}
// later
collection.search('foo', function( matches ){
_.each(matches, function(match){
console.log('found foo in '+match[0].cid+' somewhere');
});
});
Problem
I have a backbone.js collection where I need to do a fulltextsearch on. The tools I have at hand are the following: Backbone.js, underscore.js, jQuery For those not familiar with backbone: A backbones collection is just an object. Inside the collection there is an array with models. Each model has an array with attributes. I have to search each attribute for a string. The code I am using for this is: ``` query = 'some user input'; query = $.trim(query); query = query.replace(/ /gi, '|'); var pattern = new RegExp(query, "i"); // this.collection.forEach is the same as _.each // only it get's the models from the collection this.collection.forEach(function(model) { var check = true; _.each(model.attributes, function(attr){ if(pattern.test(attr) && check){ // Do something with the matched item check = false; } }, this); }, this); ``` Maybe one of the tools I am using has a better way of dealing with this ?