latitude longitude - Couchbase with PHP GeoLocation Search - (Part) Solution -
problem
i in need of search range of distance latitude , longitude. relatively straight forward in sql, however, in couchbase came across difficulty. discovered spatial views offer solution this, spatial views aren't accessible via php sdk (yet) , had use rest api alternative.
solution
i can result set within range latitude , longitude using method, need sort date created. please see end of post.
my documents such:
{ "doctype" : "post", "title" : "test post", "location" : { "latitude" : 1.123456789 "longitude" : -13.9876543210 } "created" : 1395329441 }
the trick create index normal view format keys in specific way.
the formula
- preppend keys "point::"
- add positive or negative sign "+", or "-"
- make integer part 3 characters long prepending "0"s
- make decimal part 9 characters long appending "0"
- repeat both latitude , longitude
example of key produced document above:
"point::+001.123456789,-013.987654321"
this give key formatted in way sortable unicode collation couchbase use.
the view
function (doc, meta) { if(meta.type == "json" && doc.doctype == "post" && doc.location){ if(doc.location.latitude && doc.location.longitude){ var prefix = "point::"; var latitude = doc.location.latitude.tostring(); var longitude = doc.location.longitude.tostring(); var pointkey = prefix.concat(buildkey(latitude), ",", buildkey(longitude)); emit(pointkey, meta.id); function buildkey(coord){ // positive or negative sign var sign; if(coord.substring(0,1) == "-"){ sign = "-"; coord = coord.substring(1, coord.length); } else { sign = "+"; } // remove "+" (incase there), though normall isnt expressed if(coord.substring(0,1) == "+"){ coord = coord.substring(1, coord.length); } var intsize = "000"; var decsize = "000000000"; // integer , decimal parts of latitude var parts = coord.split("."); var int = parts[0]; var dec = parts[1]; // prepend int 0's has length of 3 if(int.length < intsize.length){ int = intsize.substring(0, intsize.length - int.length) + int; } int = int.substring(0,3); // append dec 0's has length of 9 if(dec.length < decsize.length){ dec = dec + decsize.substring(0, decsize.length - dec.length); } dec = dec.substring(0,9); return sign.concat(int, ".", dec); } } } }
the php
now in php convert latitude , longitude key in same format. can work out key minimum latitude , minimum longitude , maximum latitude , maximum longitude can search "range" (range box not circle, enough narrow result set significantly)
for example:
$location = geolocation::fromdegrees($data['location']['latitude'], $data['location']['longitude']); $coordinates = $location->boundingcoordinates(50, 'miles'); $startkey = "point::" . $location->buildkey($coordinates[0]->getlatitudeindegrees()) . "," . $location->buildkey($coordinates[0]->getlongitudeindegrees()); $endkey = "point::" . $location->buildkey($coordinates[1]->getlatitudeindegrees()) . "," . $location->buildkey($coordinates[1]->getlongitudeindegrees()); $viewoptions = array( 'startkey' => $startkey, 'endkey' => $endkey ); $results = cbdatabase::$master->searchbyview("dev_posts", "by_location", $viewoptions);
the build key function follows same rules above in view. , geolocation class taken here: https://github.com/anthonymartin/geolocation.php
request
i hope helps someone. work me. if there better way of doing i'd love hear constructive feedback.
i include sort date created within range of keys. order descending in options won't work order actual location key. way can think of doing include date.created beginning of key. i'm not sure if right way go this. new couchbase guidance massively appreciated.
Comments
Post a Comment