Ранее я реализовал что-то с аналогичными требованиями и использовал HQL-запрос. Это было некоторое время назад, и я помню, что мне потребовалось много времени, чтобы прочитать и понять, так что, надеюсь, сэкономит вам время.
Это делает выбор на основе текущего местоположения (простой контейнерный объект длиной в длину) и «имени» (начинается с). Он выбирает объект домена (место проведения), а также мили вдали от текущего местоположения. Сортируется по милям по возрастанию. Примечание. Я добавил пометку «Дорожный фактор» для приблизительного расстояния до дороги.
def getVenuesInArea(venueName, location, miles, optionsMap)
{
def max = optionsMap?.max ?: 10
def offset = optionsMap?.offset ?: 0
if (venueName == null) venueName = ""
venueName += '%'
double roadFactor = 1.20 // add 20% for the roads, instead of as crow flies...
def query
def results
def countQuery = """ select count( distinct v)
from Venue as v
WHERE
v.name like :venueName AND
( acos
(
sin(radians(:lat))
* sin(radians(v.location.latitude))
+ cos(radians(:lat))
* cos(radians(v.location.latitude))
* cos(radians(v.location.longitude) - radians(:lon))
) * 3956.1676 * :roadFactor < :distance
)
"""
def count = Venue.executeQuery(countQuery, [venueName:venueName, lat:location.latitude, lon:location.longitude, distance:miles, roadFactor:roadFactor])[0]
query = """ select distinct v,
(
acos
(
sin(radians(:lat))
* sin(radians(v.location.latitude))
+ cos(radians(:lat))
* cos(radians(v.location.latitude))
* cos(radians(v.location.longitude) - radians(:lon))
)
* 3956.1676 * :roadFactor
) as milesAway
from Venue as v
WHERE
v.name like :venueName AND
( acos
(
sin(radians(:lat))
* sin(radians(v.location.latitude))
+ cos(radians(:lat))
* cos(radians(v.location.latitude))
* cos(radians(v.location.longitude) - radians(:lon))
) * 3956.1676 * :roadFactor < :distance
)
order by
(
acos
(
sin(radians(:lat))
* sin(radians(v.location.latitude))
+ cos(radians(:lat))
* cos(radians(v.location.latitude))
* cos(radians(v.location.longitude) - radians(:lon))
)
* 3956.1676 * :roadFactor
)
asc,
v.name
"""
results = Venue.executeQuery( query, [venueName:venueName, lat:location.latitude, lon:location.longitude, distance:miles, roadFactor:roadFactor, max:max, offset:offset])
def venues = []
MathContext mc = new MathContext(2)
results.each
{ result ->
VenueWithDetails venueDetails = new VenueWithDetails( venue:result[0], milesFrom:new BigDecimal(result[1]).round(mc) )
venues.add(venueDetails)
}
return [venues:venues, count:count]
}
Это было сделано на Grails версии 1.3.4, но вполне уверен, что он должен хорошо работать на 1.3.7.
Надеюсь, это поможет,
Крис.