使用关键字搜索json

时间:2017-08-10 13:43:43

标签: javascript json

我需要帮助一些我正在努力的小事。我必须创建一个通用搜索输入,搜索音乐数字的json。用户必须能够在搜索栏中键入专辑/曲目或艺术家,然后他才能获得结果。像任何其他搜索栏一样。只有这一个基于按键而不是提交按钮进行搜索。

我遇到的部分是我收到了一个包含5000多个条目的大型JSON文件。我的搜索栏必须能够根据部分键入的"关键字"来识别条目。所以,例如,如果我想搜索麦当娜,我输入" mado"我应该已经在我的结果中获得了一些麦当娜(当然可以获得其他在他们的标题中有mado的条目或者某些东西!)。

很抱歉我缺乏良好的语法,但我会尽力解释这种情况尽可能好!

现在提出问题!我正在解决的问题是我如何遍历json文件来搜索这些关键字。这是我收到的json的一小部分:

{
"1": {
    "track": "Dani California",
    "artist": "Red Hot Chili Peppers",
    "album": "Stadium Arcadium"
},
"2": {
    "track": "Tell me baby",
    "artist": "Red Hot Chili Peppers",
    "album": "Stadium Arcadium"
},
"3": {
    "track": "Snow (Hey Oh)",
    "artist": "Red Hot Chili Peppers",
    "album": "Stadium Arcadium"
}}

通常我会创建一个类似这样的函数:

for(var i = 0; i < data.length; i++){
if(data[i].album == 'red hot'){
    console.log(data[i].album)
}}

但在这种情况下,我想循环遍历json,查找包含搜索值的enties并将其保存到对象以供以后使用

是否可以一次完成所有操作?那么要一次检查艺术家/标题/专辑,还是创建一个小过滤器会更好?

如果我的解释不明确,请认识我,我尽力尽可能清楚!

2 个答案:

答案 0 :(得分:1)

我不认为搜索5000个条目会导致性能问题。 查看此代码,当您致电search('text')

时,该代码应返回所需的条目
var data = JSON.parse('JSON DATA HERE') // dataset
var search_fields = ['track','artist','album'] //key fields to search for in dataset

function search(keyword){
    if(keyword.length<1) // skip if input is empty
        return

    var results = []

    for(var i in data){ // iterate through dataset
        for(var u=0;u<search_fields.length;u++){ // iterate through each key in dataset

            var rel = getRelevance(data[i][search_fields[u]],keyword) // check if there are matches

            if(rel==0) // no matches...
                continue // ...skip

            results.push({relevance:rel,entry:data[i]}) // matches found, add to results and store relevance
        }
    }

    results.sort(compareRelevance) // sort by relevance

    for(i=0;i<results.length;i++){
        results[i] = results[i].entry // remove relevance since it is no longer needed
    }

    return results
}

function getRelevance(value,keyword){
    value = value.toLowerCase() // lowercase to make search not case sensitive
    keyword = keyword.toLowerCase()

    var index = value.indexOf(keyword) // index of the keyword
    var word_index = value.indexOf(' '+keyword) // index of the keyword if it is not on the first index, but a word

    if(index==0) // value starts with keyword (eg. for 'Dani California' -> searched 'Dan')
        return 3 // highest relevance
    else if(word_index!=-1) // value doesnt start with keyword, but has the same word somewhere else (eg. 'Dani California' -> searched 'Cali')
        return 2 // medium relevance
    else if(index!=-1) // value contains keyword somewhere (eg. 'Dani California' -> searched 'forn')
        return 1 // low relevance
    else
        return 0 // no matches, no relevance
}

function compareRelevance(a, b) {
  return b.relevance - a.relevance
}

答案 1 :(得分:0)

这是我经常用于过滤功能的模式。一些关键点是:

  1. 始终构建一个索引属性,该属性包含可过滤值的附加字符串。例如,如果可以过滤“track”,“artist”和“album”的值,则将它们的值连接到一个字符串中,并将该字符串作为其中一个属性添加到原始对象中。

    这有助于使用indexOf快速搜索,而不必在过滤时迭代每个对象。它显着提高了性能,因为不再需要这些迭代和额外的number of properties*number of objects比较。在您的情况下,每次过滤操作都会节省大约10k的比较和15k次迭代。

  2. 如果过滤器操作不区分大小写,请在将值附加到构建索引时使用toLowerCase。每次调用过滤器时,它还可以避免执行那么多toLowerCase个操作。

  3. 始终创建一个对象数组,而不是具有对象属性的对象。我没有关于这是否会提高性能的具体统计信息,但它为您提供了一些可用于改进UX的数组方法,例如array.filterarray.sort。我在片段中没有这样做,但是在准备数据时你可以很容易地做到这一点。

  4. var data = {
    "1": {
        "track": "Dani California",
        "artist": "Red Hot Chili Peppers",
        "album": "Stadium Arcadium"
    },
    "2": {
        "track": "Tell me baby",
        "artist": "Red Hot Chili Peppers",
        "album": "Stadium Arcadium"
    },
    "3": {
        "track": "Snow (Hey Oh)",
        "artist": "Red Hot Chili Peppers",
        "album": "Stadium Arcadium"
    }};
    
    // One time activity!
    // Build search indexes, for every object.
    for(var prop in data) {
      if(data.hasOwnProperty(prop)) {
        var index = "";
        var item = data[prop];
        
        // Iterate over each object and build the index by appending the values of each property.
        for(var attr in item) {
          if(item.hasOwnProperty(attr)) {
            // Note: Different values are separated by a hash as hash # is unlikely to come into the search query.
            index = index + item[attr] + "#";
          }
        }
        
        // Insert the index property into the object.
        // Also notice the toLowerCase that allows for case insenstive searches later on.
        item.index = index.toLowerCase();
      }
    }
    
    console.log("Prepared data:" ,data);
    
    // Filter process.
    var key = "Sn";
    
    var keyLowerCase = key.toLowerCase(); 
    
    // Iterate over the objects and compare the index prpoerty to match with the search string.
    var filteredData = [];
    for(var prop in data) {
      if(data.hasOwnProperty(prop)) {
        var item = data[prop];
        
        if(item.index.indexOf(keyLowerCase) >= 0 ){
          filteredData.push(item);
        }
      }
    }
    
    console.log("Filtered data:", filteredData);