DATAMONGO-2394 - Fix distance conversion for derived finder using near along with GeoJSON.

GeoJson requries the distance to be in meters instead of radians, so we now make sure to convert it correctly

Original pull request: #798.
This commit is contained in:
Christoph Strobl
2019-10-18 10:53:34 +02:00
committed by Mark Paluch
parent b5bc4320aa
commit 6959c56df6
4 changed files with 35 additions and 5 deletions

View File

@@ -29,7 +29,7 @@ import org.springframework.data.geo.Metrics;
* @author Mark Paluch
* @since 2.2
*/
class MetricConversion {
public class MetricConversion {
private static final BigDecimal METERS_MULTIPLIER = new BigDecimal(Metrics.KILOMETERS.getMultiplier())
.multiply(new BigDecimal(1000));
@@ -43,7 +43,7 @@ class MetricConversion {
* @param metric
* @return
*/
protected static double getMetersToMetricMultiplier(Metric metric) {
public static double getMetersToMetricMultiplier(Metric metric) {
ConversionMultiplier conversionMultiplier = ConversionMultiplier.builder().from(METERS_MULTIPLIER).to(metric)
.build();
@@ -56,7 +56,7 @@ class MetricConversion {
* @param distance
* @return
*/
protected static double getDistanceInMeters(Distance distance) {
public static double getDistanceInMeters(Distance distance) {
return new BigDecimal(distance.getValue()).multiply(getMetricToMetersMultiplier(distance.getMetric()))
.doubleValue();
}

View File

@@ -36,11 +36,13 @@ import org.springframework.data.geo.Shape;
import org.springframework.data.mapping.PersistentPropertyPath;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mongodb.core.geo.GeoJson;
import org.springframework.data.mongodb.core.index.GeoSpatialIndexType;
import org.springframework.data.mongodb.core.index.GeoSpatialIndexed;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
import org.springframework.data.mongodb.core.query.MetricConversion;
import org.springframework.data.mongodb.core.query.MongoRegexCreator;
import org.springframework.data.mongodb.core.query.MongoRegexCreator.MatchMode;
import org.springframework.data.mongodb.core.query.Query;
@@ -235,8 +237,14 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
criteria.near(pointToUse);
}
criteria.maxDistance(it.getNormalizedValue());
minDistance.ifPresent(min -> criteria.minDistance(min.getNormalizedValue()));
if(pointToUse instanceof GeoJson) { // using GeoJson distance is in meters.
criteria.maxDistance(MetricConversion.getDistanceInMeters(it));
minDistance.map(MetricConversion::getDistanceInMeters).ifPresent(min -> criteria.minDistance(min));
} else {
criteria.maxDistance(it.getNormalizedValue());
minDistance.ifPresent(min -> criteria.minDistance(min.getNormalizedValue()));
}
return criteria;

View File

@@ -890,6 +890,17 @@ public class QueryMapperUnitTests {
assertThat(target).isEqualTo(new org.bson.Document("_id", "id-1"));
}
@Test // DATAMONGO-2394
public void leavesDistanceUntouchedWhenUsingGeoJson() {
Query query = query(where("geoJsonPoint").near(new GeoJsonPoint(27.987901, 86.9165379)).maxDistance(1000));
org.bson.Document document = mapper.getMappedObject(query.getQueryObject(),
context.getPersistentEntity(ClassWithGeoTypes.class));
assertThat(document).containsEntry("geoJsonPoint.$near.$geometry.type", "Point");
assertThat(document).containsEntry("geoJsonPoint.$near.$maxDistance", 1000.0D);
}
@Document
public class Foo {
@Id private ObjectId id;

View File

@@ -652,6 +652,17 @@ public class MongoQueryCreatorUnitTests {
assertThat(creator.createQuery()).isEqualTo(query(where("age").gt(10).lt(11)));
}
@Test // DATAMONGO-2394
public void nearShouldUseMetricDistanceForGeoJsonTypes() {
GeoJsonPoint point = new GeoJsonPoint(27.987901, 86.9165379);
PartTree tree = new PartTree("findByLocationNear", User.class);
MongoQueryCreator creator = new MongoQueryCreator(tree,
getAccessor(converter, point, new Distance(1, Metrics.KILOMETERS)), context);
assertThat(creator.createQuery()).isEqualTo(query(where("location").nearSphere(point).maxDistance(1000.0D)));
}
interface PersonRepository extends Repository<Person, Long> {
List<Person> findByLocationNearAndFirstname(Point location, Distance maxDistance, String firstname);