Searching for text inside nested object (Backbone.js collection as example)

人盡茶涼 提交于 2020-01-22 15:42:26

问题


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 ?


回答1:


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



回答2:


Your inner each is kludging a short-circuit so you could switch to _.any() instead of your _.each() and a flag combination; 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.



来源:https://stackoverflow.com/questions/10468039/searching-for-text-inside-nested-object-backbone-js-collection-as-example

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!