在嵌套对象(例如 Backbone.js集合)中搜索文本

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

本文关键字:集合 搜索 文本 js Backbone 嵌套 对象 例如      更新时间:2023-09-26

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

Backbone.js, underscore.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);

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

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

也就是说,这只会返回集合中的第一场比赛。 您可能更喜欢以 [模型、属性] 对的形式返回结果数组的实现。

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

您的内在each正在短路,因此您可以切换到_.any()而不是_.each()和标志组合; 一旦回调函数返回trueany就会停止迭代,并且还会委托给本机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,如果"做某事"需要它们,您可以将它们放回原处。

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