How can i calculate distance in laravel5.5 with SQL query ?
My code mention below.
$specialProducts = Products::select('products.id', 'products.name', 'products.product_img', 'products.slug', 'products.price','products.lat','(3959 * ACOS(COS(RADIANS($lat))* COS(RADIANS(22.2765097))* COS(RADIANS(70.792523) - RADIANS(70.7583265))+ SIN(RADIANS(22.2897874))* SIN(RADIANS(22.2765097)))) AS distance')
->join('subcategories', 'subcategories.id', '=', 'products.sub_category_id')
->join('categories', 'categories.id', '=', 'subcategories.category_id')
->join('store', 'store.id', '=', 'products.store_id')
->where('products.status', 1)
->where('products.special', 1)
->orderBy('products.created_at', 'DESC')
->get();
If you have the values for the latitude and longitude in your DB, then you can get the distance between them using the SQl query as in the below example using raw SQL with DB:raw().
$lat = 41.118491 // user's latitude
$lng = 25.404509 // user's longitude
SELECT *,
( 6371 * acos( cos( radians($lat) )
* cos( radians( latitude ) )
* cos( radians( longitude ) - radians($lng) ) + sin( radians($lat) )
* sin( radians( latitude ) ) ) )
AS calculated_distance
FROM settings as T
HAVING calculated_distance <= (SELECT distance FROM settings WHERE sid=T.sid)
ORDER BY distance_calc
If you want to get distance in miles instead of kilometers, replace 6371 with 3959.
The calculation process may take a long time so, you might want to cache the result for next use.
It is better to do it with php instead of mysql. Check my response here.
https://stackoverflow.com/a/50040011/1262144
Related
I want to make an API using laraval which will have request of latitude and longitude and the response will provide json of location of user's nearest pharmacy
how can I do or simple example or tutorial similar ?
If you already have the latitude and longitudes in your database you might as well query them yourself. This is from an older project (so may not work or be the best method) where I'm doing something similar:
$cities = City::select(DB::raw('*, ( 6367 * acos( cos( radians('.$latitude.') ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians('.$longitude.') ) + sin( radians('.$latitude.') ) * sin( radians( latitude ) ) ) ) AS distance'))
->having('distance', '<', 25)
->orderBy('distance')
->get();
I am trying to write a mysql query in Spring JPA to find locations within a given range. (I am using Spring Boot + Kotlin)
I am trying the following query:
#Repository
interface LocationRepository : JpaRepository<LocationEntity, Long> {
#Query("SELECT id, (6371 * acos ( cos ( radians(:lat) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(:lng) ) + sin ( radians(:lat) ) * sin( radians( lat ) ))) AS distance FROM location GROUP BY address HAVING distance < :distance ORDER BY distance ASC", nativeQuery=true)
fun filterByLocation(
#Param("lat") lat: String,
#Param("lng") lng: String,
#Param("distance") distance: Int
): List<LocationEntity>
}
But I get the following error:
java.sql.SQLSyntaxErrorException: Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'my_app.location.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
My location entity is the following:
#Entity(name = "location")
data class LocationEntity(
var lat: Double,
var lng: Double
) {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0
}
I have following query:
$clinics = \DB::select('SELECT * FROM
(SELECT *,
(100 * acos(cos(radians(' . $lat . ')) * cos(radians(lat)) *
cos(radians(lng) - radians(' . $lng . ')) +
sin(radians(' . $lat . ')) * sin(radians(lat))))
AS distance
FROM clinics) AS distances
WHERE distance < 100
ORDER BY distance')
->join('countries', 'clinics.country_id', '=', 'countries.id');
When I run it I am getting following error:
Symfony \ Component \ Debug \ Exception \ FatalThrowableError (E_ERROR)
Call to a member function join() on array
Is it possible to perform JOIN with this query?
I tried adding JOIN in the select query, but I am getting an error:
Column not found: 1054 Unknown column 'clinics.country_id' in 'on clause' (SQL: SELECT * FROM (SELECT *, (100 * acos(cos(radians(43.1557012)) * cos(radians(lat)) * cos(radians(lng) - radians(22.5856811)) + sin(radians(43.1557012)) * sin(radians(lat)))) AS distance FROM clinics) AS distances JOIN countries ON countries.id = clinics.country_id WHERE distance < 100 ORDER BY distance)
The query in question:
$clinics = \DB::select('SELECT * FROM
(SELECT *,
(100 * acos(cos(radians(' . $lat . ')) * cos(radians(lat)) *
cos(radians(lng) - radians(' . $lng . ')) +
sin(radians(' . $lat . ')) * sin(radians(lat))))
AS distance
FROM clinics) AS distances
JOIN countries ON countries.id = clinics.country_id
WHERE distance < 100
ORDER BY distance');
From what I can see, the sub query is not necessary and you can transform the query into Laravel notation like so:
$clinics = Clinic::join('countries', 'countries.id', '=', 'clinics.country_id')
->selectRaw('clinics.*, countries.*, (
100 * acos(
cos(radians(?)) *
cos(radians(lat)) *
cos(radians(lng) - radians(?)) +
sin(radians(?)) * sin(radians(lat))
)
) as distance', [$lat, $lng, $lat])
->having('distance', '<', 100)
->orderBy('distance')
->get();
You might want to explicitely list which columns you want to select of the countries table because with countries.* you will override for example the id column of your clinics table. I added countries.* because I guess this is what you wanted to do after joining the tables.
I have this query:
$user = \App\User::where('id','=',191)
->whereHas('addresses', function($q){
$q->getByDistance(52.5293878, 13.3416309, 5);
})
->with(['addresses' => function($q){
$q->getByDistance(52.5293878, 13.3416309, 5);
}])
->get();
dd($user);
This picks the user with id 191, only if he has an address in range, and then he also eager loads the address.
This is the scopeGetByDistance function from the class addresses
public static function scopeGetByDistance($query,$lat, $lng, $max_distance)
{
return $query->selectRaw('lat, lng, ( 3959 * acos( cos( radians( '.$lat.') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(' . $lng . ') ) + sin( radians(' . $lat .') ) * sin( radians(lat) ) ) ) AS distance')
->having('distance', '<', $max_distance )
->orderBy( 'distance', 'ASC' );
}
I picked the user with id 191 because I know that he has an address with distance ~2 to the coordinates.
This will output a user, but the relation is empty. Shouldn't the whereHas make sure that the relation is not empty? I also know for sure that he must have an address in range. This is how the relation looks like:
I had to add the reference key to the selectRaw like this:
return $query->selectRaw('user_id, lat, lng, ( 3959 * acos( cos
I want to add laravel paginator for my select query:
the below query is working fine but not able to add laravel paginator.
$results = DB::select('SELECT
distances.*
FROM
(SELECT
( 6371 * acos( cos( radians(23.0376279 ) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(72.5102283 ) ) + sin( radians(23.0376279 ) ) * sin( radians( latitude ) ) ) ) AS distance,
shopdatabase.shop_product.stock,
shopdatabase.shop_product.price AS price,
shopdatabase.shops.id AS shopId,
shopdatabase.product.name AS name,
shopdatabase.product.id AS productId,
shopdatabase.shops.name AS shopName,
shopdatabase.shop_product.status,
shopdatabase.product_image.title AS image,
shopdatabase.product_meta.metaValue AS sourceDetails,
shopdatabase.product.sourceUrl
FROM
shopdatabase.shop_product
INNER JOIN shopdatabase.shops
ON shopdatabase.shop_product.shopId = shopdatabase.shops.id
INNER JOIN shopdatabase.product
ON shopdatabase.shop_product.productId = shopdatabase.product.id
INNER JOIN shopdatabase.product_image
ON shopdatabase.shop_product.productId = shopdatabase.product_image.productId
INNER JOIN shopdatabase.product_meta
ON shopdatabase.shop_product.productId = shopdatabase.product_meta.productId
WHERE
shopdatabase.shop_product.status = "active") distances
WHERE
distance < 20
ORDER BY
distance ASC');
Or can you tell me how can i write this select query with Eloquent?
That will be good if we can write the above code with Eloquent.
Eloquent is often not the best choice for more complex queries.
As earlier commenters have mentioned you might be able to refine this by establishing your relations.
However you should be able to paginate query builder results using paginate().
DB::select($query)->paginate(25);
Another option is to use slice() on a collection.
$collection = DB::select($query)->get();
$collection->slice(($currentPage-1) * $size, $size);
Then you need if you need a paginator to create links etc. you can create a paginator manually.
new LengthAwarePaginator(
$collection,
$total,
$size,
$currentPage
);
I suggest you read through the Laravel documentation for Eloquent and learn how to use relationships correctly.
Check out this resource: https://laravel.com/docs/5.6/eloquent-relationships
Once you set up your model relationships you should then be able to call the paginate method as specified here:
https://laravel.com/docs/5.6/pagination
You should be able to use something like this:
$foo->with('bar')->paginate();