- Published on
Sitecore Tutorial – Simple Geolocation Search in Sitecore Discover
- Authors
- Name
- Michal Strzalkowski
- @michalmadethis
A requirement which often presents itself in commerce focused websites is to search for all products 'near the user'. There are several considerations to achieving this:
- How do we determine where the user is?
- How do we structure our data in Sitecore Discover to enable this feature?
- How do we query Sitecore Discover and use that data to perform a geolocation search
Determining Search Boundary
Initially we need to determine the user’s location. Generally we need to support several mechanisms towards this, depending on device. In all cases the goal is the same : Get the user’s latitude and longtitude coordinates.
User Entered: Let’s assume the page has a form field for the user to provide a suburb or postcode. After typing a few characters the form contents are sent to a 3rd party validation service which returns a set of autocomplete suggestions or the user to pick through.
Making a selection triggers an api call to the address validation service which returns a complete location data object with the matched details (postcode, suburb, state, country etc.).
The key requirement for selecting an address validation service towards this implementation is this location object containing latitude and longitude fields.
Provided By Browser/Device: Developers can ask for the user’s latitude and longtitude on most browsers by leveraging built in javascript functions (e.g. https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API). This triggers a popup on the browser asking the user for location permissions. Depending on device settings (e.g. mobile) the browser may already have location permission.
PERMISSION MODAL
This is a very ‘sunny day’ user flow with the assumption that a user will action this popup, and must have fallbacks for the feature to work.
With the users latitude and longtitude position determined, we now need to calculate a bounding box within some radius around the user to act as a search filter. The math here has several approaches with varying accuracy vs simplicity, with many documented here: https://stackoverflow.com/questions/238260/how-to-calculate-the-bounding-box-for-a-given-lat-lng-location
For the purposes of this tutorial, let’s assume one of the simpler implementations:
function getBoundsFromLatLng(lat, lng, radiusInKm){
var lat_change = radiusInKm/111.2;
var lon_change = Math.abs(Math.cos(lat*(Math.PI/180)));
var bounds = {
lat_min : lat - lat_change,
lon_min : lng - lon_change,
lat_max : lat + lat_change,
lon_max : lng + lon_change
};
return bounds;
}
Structuring and Retrieving Data in Sitecore Discover
This solution relies on each product record in Sitecore Discover including its own separate numeric latitude and longtitude fields, with them being facetable — useable in search facets. https://doc.sitecore.com/discover/en/developers/discover-developer-guide/product-data-feed-specifications.html
These fields should be added to the product data feed (see x) as dynamic numeric attributes (see https://doc.sitecore.com/discover/en/developers/discover-developer-guide/product-data-feed-specifications.html
| dyn_attrs_numeric Format | <label>;<value>… |
| Example | latitude;37.794|longtitude;144.9785 |
Discover allows us to use faceted search (https://doc.sitecore.com/discover/en/developers/discover-developer-guide/using-faceted-search.html) to filter a numeric field against a range — e.g. search for all products between 40.
The same mechanism can be used with our user provided lat_min, lat_max, lot_min, lot_max to query the Discover Search API to locate all vehicles within our bounding box.
{
"query": {
"keyphrase": ["used wedding dress"]
},
"filter": {
"latitude": {
"value": [{"min": lat_min, "max": lat_max}]
},
{
"longtitude": {
"value": [{"min": lot_min, "max": lot_max}]
}
},
"content": {}
}
Limitations
- Can’t sort by distance
- Rounding errors due to square vs circle radius calculation
- More efficient to search for nearby stores in some cases