Im using Amazon CloudSearch as source to a JQuery Autocomplete select. It works very well, but for a reason that I`m not able to identify, when only one result is returned the encoding becomes a mess.
The solution works as follows:
Text input where people type neighborhoods or streets of a given city:
<div id="searchFormContainer">
<input type="text" value=" Digite o bairro ou rua" name="inputSearch" id="inputSearch"/>
</div>
JQuery autocomplete config:
var sourceFunction = function (request, response) {
var successFunction = function (places) {
var placesWithLabel = jQuery.map(places, function (place) {
var label = (place.addressName) ? place.addressName+', ' : '';
label += place.neighborhoodName;
var value = label;
return {label:label, value:value};
});
if(placesWithLabel.length==0){
placesWithLabel.push({label:"Não encontrado", value:""})
}
response(placesWithLabel);
}
var ajaxOptions = {appendTo: '#searchFormContainer',
url: '/textSearch', dataType: "json",
data: {strToSearch: request.term,
cityName: self.place.city.name},
success: successFunction};
jQuery.ajax(ajaxOptions);
};
var openFunction = function () {
jQuery(this).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" );
};
var closeFunction = function () {
jQuery( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" );
};
var selectFunction = function (event, data) {
if(data.item.value==""){
return;
}else{
//redirect to result page
}
};
**var autocompleteOptions = {appendTo: '#searchFormContainer',
source: sourceFunction,
minLength: 1,
open: openFunction,
close: closeFunction,
select: selectFunction};**
**$('#searchFormContainer #inputSearch').autocomplete(autocompleteOptions);**
It works successfully, calling my python view named textSearch, which does:
def textSearch(request):
results = simplejson.loads(requests.get('http://%s/2011-02-01/search?' % (settings.SEARCH_CLOUD_HOST), params=fieldsParameter).text)['hits']
return HttpResponse(simplejson.dumps(results), mimetype='application/json')
Taking for example a search for the street named Oscar Freire in neighbourhood Cerqueira César, when I type Oscar Fr in the autocomplete, Amazon CloudSearch returns me two results:
[16/Apr/2013 23:59:47] "GET /textSearch?strToSearch=Oscar+F&cityName=S%C3%A3o+Paulo HTTP/1.1" 200 682
Neighbourhood from Amazon --> Cerqueira César
Returns from Amazon --> {'id_address': u'52267', 'neighborhoodName': u'Cerqueira C\xe9sar', 'addressName': u'Rua Oscar Freire', 'id_neighborhood': u'19694'}
Neighbourhood from Amazon --> Jardim Anália Franco
Returns from Amazon --> {'id_address': u'61073', 'neighborhoodName': u'Jardim An\xe1lia Franco', 'addressName': u'Rua Jos\xe9 Oscar Abreu Sampaio', 'id_neighborhood': u'19881'}
But, typing one more letter with the search keyword Oscar Fre, which returns only one result I`ve:
[16/Apr/2013 23:59:49] "GET /textSearch?strToSearch=Oscar+Fr&cityName=S%C3%A3o+Paulo HTTP/1.1" 200 286
Neighbourhood from Amazon --> Cerqueira CĂŠsar
Returns from Amazon --> {'id_address': u'52267', 'neighborhoodName': u'Cerqueira C\u0102\u0160sar', 'addressName': u'Rua Oscar Freire', 'id_neighborhood': u'19694'}
As we can see in the output, the returned object is the same (id_address is the same for both results). The amazon object (RAW JSON extracted from CloudSearch) for this entry is:
{"rank":"-text_relevance","match-expr":"(label 'Oscar Freire')","hits":{"found":1,"start":0,"hit":[{"id":"52267","data":{"address":["Rua Oscar Freire"],"bairro":["Cerqueira César"],"fieldtype":["address"],"id_address":["52267"],"id_neighborhood":["19694"],"latitude":["-23.568315"],"longitude":["-46.66293"],"text_relevance":["310"]}}]},"info":{"rid":"e2467862eecf73","time-ms":3,"cpu-time-ms":0}}
For me is clear the fact that the response is coming with wrong encoding to my python view.. But I can`t realize where this problem begins. If it is a bad behaviour from JQuery autocomplete or a problem with Amazon response. Any ideas?
Best Regards
I think it's important to isolate the possible causes of the issue. There are too many possible sources of encoding problems here, you should start with removing possible sources of problems.
If you search for "Oscar Fr" vs. "Oscar F" in a browser (using the CloudSearch search endpoint), does the encoding change at all? If it stays the same, then the problem is not CloudSearch, and you can move up the stack.
Related
I've been researching A LOT for past 2 weeks and can't pinpoint the exact reason of my Meteor app returning results too slow.
Currently I have only a single collection in my Mongo database with around 2,00,000 documents. And to search I am using Meteor subscriptions on the basis of a given keyword. Here is my query:
db.collection.find({$or:[
{title:{$regex:".*java.*", $options:"i"}},
{company:{$regex:".*java.*", $options:"i"}}
]})
When I run above query in mongo shell, the results are returned instantly. But when I use it in Meteor client, the results take almost 40 seconds to return from server. Here is my meteor client code:
Template.testing.onCreated(function () {
var instance = this;
// initialize the reactive variables
instance.loaded = new ReactiveVar(0);
instance.limit = new ReactiveVar(20);
instance.autorun(function () {
// get the limit
var limit = instance.limit.get();
var keyword = Router.current().params.query.k;
var searchByLocation = Router.current().params.query.l;
var startDate = Session.get("startDate");
var endDate = Session.get("endDate");
// subscribe to the posts publication
var subscription = instance.subscribe('sub_testing', limit,keyword,searchByLocation,startDate,endDate);
// if subscription is ready, set limit to newLimit
$('#searchbutton').val('Searching');
if (subscription.ready()) {
$('#searchbutton').val('Search');
instance.loaded.set(limit);
} else {
console.log("> Subscription is not ready yet. \n\n");
}
});
instance.testing = function() {
return Collection.find({}, {sort:{id:-1},limit: instance.loaded.get()});
}
And here is my meteor server code:
Meteor.publish('sub_testing', function(limit,keyword,searchByLocation,startDate,endDate) {
Meteor._sleepForMs(200);
var pat = ".*" + keyword + ".*";
var pat2 = ".*" + searchByLocation + ".*";
return Jobstesting.find({$or:[{title:{$regex: pat, $options:"i"}}, { company:{$regex:pat,$options:"i"}},{ description:{$regex:pat,$options:"i"}},{location:{$regex:pat2,$options:"i"}},{country:{$regex:pat2,$options:"i"}}],$and:[{date_posted: { $gte : endDate, $lt: startDate }},{sort:{date_posted:-1},limit: limit,skip: limit});
});
One point I'd also like to mention here that I use "Load More" pagination and by default the limit parameter gets 20 records. On each "Load More" click, I increment the limit parameter by 20 so on first click it is 20, on second click 40 and so on...
Any help where I'm going wrong would be appreciated.
But when I use it in Meteor client, the results take almost 40 seconds to return from server.
You may be misunderstanding how Meteor is accessing your data.
Queries run on the client are processed on the client.
Meteor.publish - Makes data available on the server
Meteor.subscribe - Downloads that data from the server to the client.
Collection.find - Looks through the data on the client.
If you think the Meteor side is slow, you should time it server side (print time before/after) and file a bug.
If you're implementing a pager, you might try a meteor method instead, or
a pager package.
I am trying to use Twitter typeahead but I am facing a problem. I don't know how typeahead passes the string to the server. Is it through a GET parameter? If so, what is the name of the parameter?
Easiest through a GET parameter, you can choose whatever parameter you want.
In JS:
$('#search').typeahead({
name: 'Search',
remote: '/search.php?query=%QUERY' // you can change anything but %QUERY, it's Typeahead default for the string to pass to backend
});
In PHP (or whatever backend you have):
$query = $_GET['query'];
Hope you get the basic idea.
You might want to consider something like this, it is a very basic remote datasource example. The get parameter in this example is 'q'
// Get your data source
var dataSource = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: 'path/to/your/url/json/datasource/?q=%QUERYSTRING',
wildcard: '%QUERYSTRING'
}
});
// initialize your element
var $typehead = $('#form input').typeahead(null, {
source: dataSource
});
// fire a select event, what you want once a user has selected an item
$typehead.on('typeahead:select', function(obj, datum, name) {
//your code here
});
////////////////////////////////////
# in python (django) we get a query string using the request object passed through a view like this
query = request.GET.get('q') or ""
//the caveat [or ""] is just to prevent null exceptions
///////////////////////////////////
# using php
$query = ($_GET['q']) ? $_GET['q'] : "";
I am working on a facebook mobile web app. There is the following function.
function getUserFriends() {
FB.api('/me/friends&fields=name,picture', function(response) {
console.log('Got friends: ', response);
if (!response.error) {
var markup = '';
var friends = response.data;
for (var i=0; i < friends.length && i < 25; i++) {
var friend = friends[i];
markup += '<img src="' + friend.picture + '"> ' + friend.name + '<br>' + friend.id + '<br>';
}
document.getElementById('user-friends').innerHTML = markup;
}
});
}
When it returns the pictures are missing.
The console log returns:
[06:02:12.503] GET http://m.mochirestaurant.com/fb/%5Bobject%20Object%5D [HTTP/1.1 404 Not Found 77ms]
While it should return something like:
http://profile.ak.fbcdn.net/hprofile-ak-ash2/276211_285403872_5043326_q.jpg
I think I misconfigured something in my facebook app but don't know what it is
[06:02:12.503] GET http;//m.mochirestaurant.com/fb/%5Bobject%20Object%5D [HTTP/1.1 404 Not Found 77ms]
Instead of a real value you can see that it says [object] in there (with the brackets URL-encoded) – which is what browsers return when you are trying to bring an object into a string context. (And because that is not a full URL beginning with http://…, your browser treats it as a relative address and tries to request it from your domain.)
So obviously friend.picture at this point in your code is not a string value, but an object.
(So far for the debugging and spotting-the-error-part.)
This stems from the October 3, 2012 Breaking change regarding the user/picure connection,
/picture connection will return a dictionary when a callback is specified
We will start returning a dictionary containing the fields url, height, width, and is_silhouette when accessing the /picture connection for an object and specifying a callback property. Currently we just return the picture URL as a string.
So you have to use friend.picture.url in your code to get the actual string property containing the user picture’s URL.
I'm new with Django + Ajax. My Problem is I can't get the value from my ajax POST request. I'm using the jquery post.
My task is to sort the draggable list item. The drag and drop is not the problem. Getting the values from POST request is the problem. It returns MultiValueDictKeyError
"Key 'ages' not found in <QueryDict: {u'action': [u'updateRecords'], u'ages[]': [u'80', u'81', u'79', u'82', u'83', u'84', u'85', u'86']}>"
here is my ajax:
$(function() {
var url = ""; /* won't place it*/
$("ul#ages").sortable({ opacity: 0.6, cursor: 'move', update: function() {
var order = $(this).sortable("serialize") + '&action=updateRecords';
$.post(url, order, function(theResponse){
alert('success');
});
}
});
});
here is the views:
if request.is_ajax():
if request.POST['action'] == "updateRecords":
update_record_array = request.POST['ages']
order_counter = 1;
for record_id in update_record_array:
Age.objects.filter(id=record_id).update(order_id=order_counter)
order_counter += 1
Can anyone help me out?
Thanks!
The error message shows what is wrong - you're looking up a key ages, but you're sending something called ages[] with some extra square brackets.
If you've put those brackets in the field name, you don't need them - that's a PHP-ism. (It might not be your fault: jQuery has been known to do add them itself.) In any case, you'll want to use request.POST.getlist(fieldname) to get the list of multiple values associated with that key.
I am quite new to Django and jquery stuff. I am trying to populate a comboBox (ChoiceField in Django) based ont the choice selected in another comboBox (without reloading the page).
I can't find any simple example of such a basic application of ajax.
For now I'm call the following ajax function when I select an item from the first dropdown list.
function get_asset_from_type(){
var type_asset = $("#id_type").val();
var data = {type_asset:type_asset};
var args = {type:"POST", url:"/asset/etatType/", data:data};
$.ajax(args);
alert(type_asset);
return false;
};
It alerts the right type but gives a 403 error on the given url. Weird thing is this url works the first time I load the page. I don't understand what's going on..
EDIT:
403 error seems to be gone, remains the initial question :)
I think you're running up against a CSRF problem. As Django by default blocks POST requests that do not have a CSRF Token with a 403. There are a couple ways to deal with this in JS. One is to pull the value out of the cookie, the code to do that can be found here: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax
or you can do it by passing the CSRF_TOKEN in with the javascript script tag:
<script src='myjavascript.js?CSRF_TOKEN={{ csrf_token }}'></script>
Note that it's using a double braket, instead of {%%}. This gets the value of the token, instead of the form input.
function getOptionsFromScriptSrc() {
// Get last script tag in parsed DOM.
// Due to the way html pages are parsed,
// the last one is always the one being loaded.
var options = {}
var js_src = $('script').last().attr('src');
if(js_src.match(/\?/)) {
var options_list = js_src.split('?')[1].split('&');
for(var i = 0; i < options_list.length; i++) {
var tmp = options_list[i].split('=');
options[$.trim(tmp[0])] = $.trim(tmp[1]);
}
}
return options;
}
function get_asset_from_type(){
var options = getOptionsFromScriptSrc();
var type_asset = $("#id_type").val();
var data = {type_asset: type_asset, csrfmiddlewaretoken: options['CSRF_TOKEN']};
var args = {type:"POST", url:"/asset/etatType/", data:data};
$.ajax(args);
alert(type_asset);
return false;
};
I haven't, of course, tested this code, but I have used this method before and it works pretty well.
To the main problem of populating a select box, you need to specify a callback for your ajax post, and then deal with the data returned from your server:
function get_asset_from_type(){
var options = getOptionsFromScriptSrc();
var type_asset = $("#id_type").val();
var post_data = {type_asset: type_asset, csrfmiddlewaretoken: options['CSRF_TOKEN']};
$.post('/asset/etatType/', post_data, function(data){
// Assuming server is going to respond with the html of the options, eg: <option value="1">One</option><option value="2">Two</option>...
$('#id_ofmyselectbox').append(data);
});
};