javascript - Searching for text inside nested object (Backbone.js collection as example) - Stack Overflow

I have a backbone.js collection where I need to do a fulltextsearch on. The tools I have at hand are th

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 ?

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 ?

Share Improve this question edited Sep 1, 2015 at 13:13 user3335966 2,7444 gold badges32 silver badges33 bronze badges asked May 6, 2012 at 4:13 Saif BechanSaif Bechan 17.1k23 gold badges85 silver badges125 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 4

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');
  });
});

Your inner each is kludging a short-circuit so you could switch to _.any() instead of your _.each() and a flag bination; any stops iterating as soon as the callback function returns true and also delegates to the native some method if available.

this.collection.each(function(model) {
    _(model.attributes).any(function(attr, key) {
        if(!pattern.test(attr))
            return false;
        // Do something with the matched item...
        return true;
    });
});

I also dropped the context this arguments since you're not using this anywhere, you can put them back if the "Do something" needs them.

You could look into stemming and a reverse index of the collection if a simple regex search isn't good enough.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1742297245a4417372.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信