How to search nearby places using Strapi without broking the query system
Hello folks, if you are there, it means that you have been looking for a way to make geo query using strapi unsuccessfully, in this article I will show you how to tacle it.
This article suppose you are able to run a Strapi project without any issue , so in this article we will be focused on how to handle a request like this http://localhost:1337/items?_latitude=3.888360&_longitude=11.51290&_distance=500 , basically we are trying to fetch all items 500 meters around the point (3.888360,11.51290).
To do so,let say we have created a model named “item”, you will need to save latitude and longitude of each items, so this is how my file /api/item/models/item.settings.json will look like :
{ "kind": "collectionType", "collectionName": "items", "info": { "name": "Places", "description": "" }, "options": { "increments": true, "timestamps": true, "draftAndPublish": true }, "pluginOptions": { "i18n": { "localized": true } }, "attributes": { "latitude": { "type": "float", "pluginOptions": { "i18n": { "localized": true } } }, "longitude": { "type": "float", "pluginOptions": { "i18n": { "localized": true } } } }}
Now open you file /api/item/service/item.js
const { convertRestQueryParams, buildQuery } = require(‘strapi-utils’);
Override the find method:
module.exports = {async find(params, populate, { transacting } = {}) {const latitude=params._latitude;const longitude=params._longitude;const distance=params.distance;const isGeoQuery = latitude && longitude && distance;delete params._latitude;delete params._longitude;delete params.distance;const distanceInMilesSql=`ST_distance_sphere( point(latitude, longitude), point(${latitude}, ${longitude})) as distance`;const knex = strapi.connections.default;const filters = convertRestQueryParams(params);const model = strapi.models.item;const query = buildQuery({ model, filters });return model.query(qb=>{if(isGeoQuery){console.log('Is geo query');qb.column(knex.raw(distanceInMilesSql));qb.having('distance','<',distance);qb.orderBy('distance');}query(qb);}).fetchAll({withRelated: populate,transacting,publicationState: filters.publicationState,}).then(results => results.toJSON());}
That is all, now you can query items around a specified point without broking the existing filter feature.
