4

我有一个backbone.js 集合,我需要在其中进行全文搜索。我手头的工具如下:

Backbone.js、下划线.js、jQuery

对于那些不熟悉骨干的人:

主干集合只是一个对象。在集合内有一个带有模型的数组。每个模型都有一个带有属性的数组。我必须在每个属性中搜索一个字符串。

我为此使用的代码是:

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

也许我正在使用的工具之一有更好的方法来处理这个问题?

4

2 回答 2

4

Backbone 将许多下划线方法扩展到Collection类中,因此您可以摆脱其中的一些内容。真的,您可能想在集合本身上将其作为一种方法来暗示,然后我可能会使用一个好的老式for循环来查看这些键,特别是如果我想打破它。

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

也就是说,这只会返回集合中的第一个匹配项。您可能更喜欢将结果数组作为 [model, attribute] 对返回的实现。

// 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]);
  });
});

或者,如果您想要一组匹配但不关心匹配哪个属性的模型,您可以使用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');
  });
});
于 2012-05-06T04:49:53.490 回答
2

你的内心each正在拼凑一个短路,所以你可以切换到_.any()而不是你_.each()和一个标志的组合;any一旦回调函数返回就停止迭代,true并且如果可用,还委托给本机some方法。

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

我还删除了上下文this参数,因为您没有this在任何地方使用,如果“做某事”需要它们,您可以将它们放回去。

如果简单的正则表达式搜索不够好,您可以查看词干提取和集合的反向索引。

于 2012-05-06T04:51:07.443 回答