I am having some trouble with Algolia's geo search feature which was working properly before. Here is the record of interest.
I also had that indexed as described by the doc in order for me to sort it by the nearest distance:
'attributesToIndex' => ['name', 'description', 'geo']
In my client script:
let settings = {
aroundLatLng: '10.309813,123.893154',
getRankingInfo: true,
aroundRadius: 2000
};
index.search(keyword, settings, (err, data) => {
console.log(data);
});
But this gives me 0 hit. Notice the aroundLatLng
value -- its the same value from the record of interest.
Am I missing something here?
My bad. Malformed indexed data for _geoloc. Should be keyed with lat
and lng
I have implemented same requirement in node.js as per given in document and its working fine. Here i am copying my whole code. Hopefully it may help you.
Code
/*
I have used async.water model to create the setting of the index and then searching data as per given parameter. few function is custom so no need to bother about that. read each line patently.
*/
try {
var self = this;
var post = req.body;
var user_id = post.user_id;
var created_mode = post.user_mode == 'requester' ? 'provider' : 'requester';
var kword = post.kword;
var geo = post.geo_loc;
var aroundLatLng = post.aroundLatLng;
var aroundRadius = !cmnFn.empty(post.radious) ? post.radious : 4500;
var hitsPerPage = !cmnFn.empty(post.hitsPerPage) ? post.hitsPerPage : 20;
var offset = !cmnFn.empty(post.offset) ? post.offset : 0;
var length = !cmnFn.empty(post.length) ? post.length : 50;
var budget_from = !cmnFn.empty(post.budget_from) ? post.budget_from : 0;
var budget_to = !cmnFn.empty(post.budget_to) ? post.budget_to : 0;
var day_preference = !cmnFn.empty(post.day_preference) ? post.day_preference : '';
var time_preference = !cmnFn.empty(post.time_preference) ? post.time_preference : '';
var start_date = !cmnFn.empty(post.start_date) ? post.start_date : '';
job_index is index created on Algolia
var job_index = algClient.initIndex('jobs');
var cond = {};
If you are using facet & filter then you need to use filter key to execute your condition same as you may have done in sql using where clouse
cond.filters = 'created_mode:"' + created_mode + '" AND (NOT user_id:"' + user_id + '")';
// Query which need to be search
if (!cmnFn.empty(kword)) {
cond.query = !cmnFn.empty(post.kword) ? post.kword : '';
}
if ((!cmnFn.empty(budget_from) && !cmnFn.empty(budget_to)) && budget_from > 0) {
cond.filters += ' AND min_charge: ' + budget_from + ' TO ' + budget_to;
}
if (!cmnFn.empty(day_preference)) {
cond.filters += ' AND day_preference:"' + day_preference + '"';
}
if (!cmnFn.empty(time_preference)) {
cond.filters += ' AND time_preference:"' + time_preference + '"';
}
if (!cmnFn.empty(start_date) && (new Date(start_date)).getTime() > 0) {
cond.filters += ' AND start_date:"' + start_date + '"';
}
Here i am setting aroundLatLng to get data nearest to far
/*
Do not fogot one thing, before using geo search, your records must have _geoloc key having following format
"_geoloc": {
"lat": 40.639751,
"lng": -73.778925
}
*/
// Around geo search by given lat lng
if (!cmnFn.empty(aroundLatLng) && !cmnFn.empty(aroundLatLng.lat)) {
cond.aroundLatLng = aroundLatLng.lat + ', ' + aroundLatLng.lng;
if (!cmnFn.empty(aroundRadius) && cond.aroundRadius > 0) {
cond.aroundRadius = aroundRadius;
}
}
// total number of searched record
if (!cmnFn.empty(hitsPerPage)) {
cond.hitsPerPage = hitsPerPage;
}
// Record starting position
if (!cmnFn.empty(offset)) {
cond.offset = offset;
}
// Page Limitation
if (!cmnFn.empty(length)) {
cond.length = length;
}
// Don't show attributesToHighlight in result set
cond.attributesToHighlight = false;
/*
restrictSearchableAttributes: List of object key, where to search in given list defined in searchableAttributes
*/
cond.restrictSearchableAttributes = [
'user_id',
'title',
'description',
'_geoloc'
];
/*
It will return raning info of result when search come under geo search
Following output will return
"_rankingInfo": {
"nbTypos": 0,
"firstMatchedWord": 0,
"proximityDistance": 0,
"userScore": 31,
"geoDistance": 9, // Calculated distance between data geolocation given in _geoloc and search criteria in aroundLatLng
"geoPrecision": 1,
"nbExactWords": 0,
"words": 1,
"filters": 0,
"matchedGeoLocation": {
"lat": 28.5503,
"lng": 77.2501,
"distance": 9
}
}
*/
cond.getRankingInfo = true;
async.waterfall([
function (callback) {
job_index.setSettings({
'attributesForFaceting': ['user_id', 'created_mode', 'min_charge', 'day_preference', 'time_preference', 'start_date'],
/*
searchableAttributes: List of object key , where to search
eg: ['title', 'description']
Like in sql: Where title='your searched text' AND description='your searched text'
_geoloc is reserved keyword of algolia which will used to search geo location
*/
searchableAttributes: [
'title',
'description',
'user_id',
'_geoloc'
],
/*
attributesToRetrieve: Here you can specify list of key name which you want to retrive
eg: ['name','address','age']
Like in sql: Select name, address, age
*/
attributesToRetrieve: [
'*'
]
}).then(() => {
return callback(null, 'success');
});
}
], function (err, results) {
if (err) {
console.log('error: ' + err);
}
job_index.search(cond).then(results => {
if (results.nbHits > 0) {
var rows = new Array();
for (i in results.hits) {
var row = {};
var item = results.hits[i];
var user_info = {};
user_info = item.user_info;
// Get distance and calculate
if (!cmnFn.empty(item._rankingInfo)) {
item.distance = cmnFn.meterToKM(item._rankingInfo['geoDistance']);
} else {
let loc = {
geoLoc_1: { latitude: aroundLatLng.lat, longitude: aroundLatLng.lng },
geoLoc_2: { latitude: item._geoloc.lat, longitude: item._geoloc.lng }
}
cmnFn.getDistance(loc, function (distance) {
item.distance = distance
})
}
/* self.isFav({ user_id: item.user_id, job_id: item.job_id }), function (err, flag) {
item.is_favorite = flag;
}; */
self.isFav({ user_id: item.user_id, job_id: item.job_id }).then(function (flag) {
item.is_favorite = flag;
}, function (err) {
item.is_favorite = false;
});
if (cmnFn.empty(item.currency)) {
item.currency = "₹";
}
//Delete few key from object which does not need to send in response
delete item['user_info'];
delete item['objectID'];
delete item['_geoloc'];
delete item['_rankingInfo'];
row.job_info = item;
row.user_info = user_info;
rows.push(row);
}
info = { status: 1, message: util.format(lang.TOTAL_RECORD_FOUND, results.nbHits), data: rows };
cmnFn.showMsg(res, info);
} else {
info = { status: 0, message: lang.RECORD_NOT_FOUND, data: null };
cmnFn.showMsg(res, info);
}
}).catch(err => {
console.log(err);
info = { status: 0, message: lang.RECORD_NOT_FOUND, data: null };
cmnFn.showMsg(res, info);
});
//res.end('' + JSON.stringify(results));
});
} catch (error) {
info = { status: 0, message: lang.RECORD_NOT_FOUND, data: null };
cmnFn.showMsg(res, info);
}