Callum Whyte
Callum Whyte

Reputation: 2429

Ordering results in JSON variable by integer

I am building a jQuery search suggestion script based upon two Google API's. Each API outputs a "relevance" integer (which I am returning next to each item to demonstrate) and I want to be able to order the results by that integer for each item.

How can I do this? I tried making the script output everything into one variable but I couldn't quite work it out.

A working demo can be seen here: http://jsfiddle.net/rEPf3/

My jQuery code is:

$(document).ready(function(){
    $("#search").keyup(function(){
        $.getJSON("http://suggestqueries.google.com/complete/search?q="+$("#search").val()+"&client=chrome&callback=?",function(data){
            var suggestion="";
            for(var key in data[1]){
                if(data[4]["google:suggesttype"][key]=="NAVIGATION"){
                suggestion+="<li><a href='"+data[1][key]+"'>"+data[2][key]+"</a> <i>("+data[4]["google:suggestrelevance"][key]+")</i></li>";
                }else{
                suggestion+="<li>"+data[1][key]+" <i>("+data[4]["google:suggestrelevance"][key]+")</i></li>";
                }
            }
            $("#suggest").html(suggestion);
        });
        $.getJSON("https://www.googleapis.com/freebase/v1/search?query="+$("#search").val()+"&limit=3&encode=html&callback=?",function(data){
            var suggestion2="";
            for(var key in data.result){
                suggestion2+="<li>"+data.result[key].name+" <i>("+data.result[key].score*4+")</i></li>";
            }
            $("#suggest2").html(suggestion2);
        });
    });
});

Upvotes: 1

Views: 405

Answers (4)

Richard Marr
Richard Marr

Reputation: 3064

I think the cleanest way is to push the results from each dataset into an externally scoped variable, then sort and render from that. Example is below.

var combined = [],
    completed = 0;

$(document).ready(function () {
    $("#search").keyup(function () {
        combined = [];
        completed = 0;
        $.getJSON("http://suggestqueries.google.com/complete/search?q=" + $("#search").val() + "&client=chrome&callback=?", function (data) {
            for (var key in data[1]) {
                if (data[4]["google:suggesttype"][key] == "NAVIGATION") {
                    combined.push({
                        href : data[1][key],
                        text : data[2][key],
                        score : parseInt(data[4]["google:suggestrelevance"][key],10)
                    });
                } else {
                    combined.push({
                        text : data[1][key],
                        score : parseInt(data[4]["google:suggestrelevance"][key],10)
                    });
                }
            }
            if ( ++completed == 2 ) complete();
        });
        $.getJSON("https://www.googleapis.com/freebase/v1/search?query=" + $("#search").val() + "&limit=3&encode=html&callback=?", function (data) {
            for (var key in data.result) {
                combined.push({
                    text : data.result[key].name,
                    score : parseInt(data.result[key].score,10) * 14
                });
            }
            if ( ++completed == 2 ) complete();
        });
    });
});


function complete(){
    console.log(combined);
    combined.sort(function(a,b){ return b.score - a.score; });
    var buffer = [];
    combined.forEach(function(result){
        buffer.push("<li>"+result.text+" <i>("+result.score+")</i></li>")
    })
    $("#suggest").html(buffer.join(""));
}

Edit

This solution doesn't take into account the fact that the user may be typing at a faster pace than the APIs, that API calls may not come back in order, and doesn't do anything to try to limit the number of calls made to each API. To make this behave more consistently (and more efficiently):

  • Change the keypress handler such that each key press cancels any previous timeouts then sets a new timeout at a reasonable delay (300ms seems a reasonable place to start) which then triggers the API calls
  • Wrap each API call in an immediately executed function so that you can reference the value of a global counter at the time each API call was made. Increment the counter with each keypress, and don't process the response from API calls where the counter didn't match

Upvotes: 1

Vishwanath
Vishwanath

Reputation: 6004

Put them together and sort.

Following is the code.
Using promise to know both ajax requests are completed.

$(document).ready(function(){
    $("#search").keyup(function(){
        var mergedData = [];
    var promise1 = $.getJSON("http://suggestqueries.google.com/complete/search?q="+$("#search").val()+"&client=chrome&callback=?",function(data){
        var suggestion="";
        console.log(data);
        var arr  = [];
        for(var i in data[1]){
        arr[i] = {value : data[1][i], rel : data[4]['google:suggestrelevance'][i]};
        }

        $.extend(mergedData,arr);

        arr.sort(function(a, b){
            return (b['rel']-a['rel']);
        });


    });
    var promise2 = $.getJSON("https://www.googleapis.com/freebase/v1/search?query="+$("#search").val()+"&limit=3&encode=html&callback=?",function(data){
        console.log('data of second request', data);
        var suggestion2="";
        var arr = [];
        for(var key in data.result){
            arr[key] = {value : data.result[key].name, rel : data.result[key].score};
        }
        $.extend(mergedData,arr);
        $("#suggest2").html(suggestion2);
    });



        $.when(promise1, promise2).then(function(){
             mergedData.sort(function(a, b){
            return (b['rel']-a['rel']);
        });
            var suggestion = '';
            for(var key in mergedData){
                suggestion+='<li>' + mergedData[key].value + ' ' + mergedData[key].rel + '</li>';
            }    
            $("#suggest").html(suggestion);
        });
    });



});

Updated working jsfiddle : http://jsfiddle.net/rEPf3/13/

Upvotes: 0

Dineshkani
Dineshkani

Reputation: 3015

Try like this

Add this line before to the for loop

data[4]["google:suggestrelevance"].sort();

See Demo

Updated

Try combining the data sets by using a single variable

See Demo

Upvotes: 0

Chamika Sandamal
Chamika Sandamal

Reputation: 24302

Here is the full code for you, you have to append all the results to one container and sort in .ajaxComplete event

$(document).ready(function () {
    $("#search").keyup(function () {
        $("#suggest").empty();
        $.getJSON("http://suggestqueries.google.com/complete/search?q=" + $("#search").val() + "&client=chrome&callback=?", function (data) {
            var suggestion = "";

            for (var key in data[1]) {
                if (data[4]["google:suggesttype"][key] == "NAVIGATION") {
                    suggestion += "<li><a href='" + data[1][key] + "'>" + data[2][key] + "</a> <i>(" + data[4]["google:suggestrelevance"][key] + ")</i></li>";
                } else {
                    suggestion += "<li>" + data[1][key] + " <i>(" + data[4]["google:suggestrelevance"][key] + ")</i></li>";
                }
            }
            $("#suggest").append(suggestion);
        });
        $.getJSON("https://www.googleapis.com/freebase/v1/search?query=" + $("#search").val() + "&limit=3&encode=html&callback=?", function (data) {
            var suggestion2 = "";
            for (var key in data.result) {
                suggestion2 += "<li>" + data.result[key].name + " <i>(" + data.result[key].score * 4 + ")</i></li>";
            }
            $("#suggest").append(suggestion2);

        });
        $(document).ajaxComplete(function (event, xhr, settings) {
            $("#suggest").html($("#suggest li").sort(function (a, b) {
                return (parseInt($(a).find("i").html(), 10) > parseInt($(b).find("i").html(), 10));

            }));
        });
    });
});

http://jsfiddle.net/rEPf3/8/

Upvotes: 1

Related Questions