4

我有一個backbone.js集合,我需要對其進行全文搜索。我手邊的工具如下:在嵌套對象中搜索文本(以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); 

也許我在用的有一個處理的更好方式的手段之一?

回答

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

感謝您的回答。正常for..in將會很好。 –

2

你內心each是kludging短路,所以你可以切換到_.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參數,你可以把他們回來,如果該「做什麼」需要他們。

如果簡單的正則表達式搜索不夠好,您可以查看集合的詞幹和反向索引。

+0

提及_.any +1。不知道這存在,它看起來非常方便。我也會調查干擾,也從未聽說過。但是一個正常的正則表達式現在還不錯。 –

+0

這比接受的答案要好得多。 – rudolph9