【问题标题】:Searching for text inside nested object (Backbone.js collection as example)在嵌套对象中搜索文本(以 Backbone.js 集合为例)
【发布时间】:2012-05-06 04:13:48
【问题描述】:

我有一个backbone.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);

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

【问题讨论】:

    标签: javascript jquery backbone.js full-text-search underscore.js


    【解决方案1】:

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

    【讨论】:

    • 感谢您的回答。一个普通的 for..in 就可以了。
    【解决方案2】:

    你内心的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,如果“做某事”需要它们,您可以将它们放回去。

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

    【讨论】:

    • +1 用于提及 _.any。不知道有这个,看起来很方便。我也会研究词干,也从未听说过。但是现在正常的正则表达式就可以了。
    猜你喜欢
    • 2020-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-04
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    相关资源
    最近更新 更多