DATAMONGO-1136 - Use $geoWithin instead of $within for geo queries.
We now use the $geoWithin operator for geospatial criteria which requires to run on at least MongoDB 2.4. Original pull request: #263.
This commit is contained in:
committed by
Oliver Gierke
parent
5ed7e8efc2
commit
59e54cecd2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 the original author or authors.
|
||||
* Copyright 2010-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -376,8 +376,8 @@ public class Criteria implements CriteriaDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a geospatial criterion using a {@literal $within $centerSphere} operation. This is only available for Mongo
|
||||
* 1.7 and higher.
|
||||
* Creates a geospatial criterion using a {@literal $geoWithin $centerSphere} operation. This is only available for
|
||||
* Mongo 2.4 and higher.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/operator/query/geoWithin/
|
||||
* @see http://docs.mongodb.org/manual/reference/operator/query/centerSphere/
|
||||
@@ -386,12 +386,12 @@ public class Criteria implements CriteriaDefinition {
|
||||
*/
|
||||
public Criteria withinSphere(Circle circle) {
|
||||
Assert.notNull(circle);
|
||||
criteria.put("$within", new GeoCommand(new Sphere(circle)));
|
||||
criteria.put("$geoWithin", new GeoCommand(new Sphere(circle)));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a geospatial criterion using a {@literal $within} operation.
|
||||
* Creates a geospatial criterion using a {@literal $geoWithin} operation.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/operator/query/geoWithin/
|
||||
* @param shape
|
||||
@@ -400,7 +400,7 @@ public class Criteria implements CriteriaDefinition {
|
||||
public Criteria within(Shape shape) {
|
||||
|
||||
Assert.notNull(shape);
|
||||
criteria.put("$within", new GeoCommand(shape));
|
||||
criteria.put("$geoWithin", new GeoCommand(shape));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,11 +21,13 @@ import org.springframework.data.geo.Polygon;
|
||||
import org.springframework.data.geo.Shape;
|
||||
import org.springframework.data.mongodb.core.geo.Sphere;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Wrapper around a {@link Shape} to allow appropriate query rendering.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @since 1.5
|
||||
*/
|
||||
public class GeoCommand {
|
||||
@@ -82,4 +84,41 @@ public class GeoCommand {
|
||||
|
||||
throw new IllegalArgumentException("Unknown shape: " + shape);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 0;
|
||||
result += ObjectUtils.nullSafeHashCode(this.command);
|
||||
result += ObjectUtils.nullSafeHashCode(this.shape);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof GeoCommand)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GeoCommand that = (GeoCommand) obj;
|
||||
if (!ObjectUtils.nullSafeEquals(this.command, that.command)) {
|
||||
return false;
|
||||
}
|
||||
return ObjectUtils.nullSafeEquals(this.shape, that.shape);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,216 +1,176 @@
|
||||
/*
|
||||
* Copyright 2010-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.mongodb.core.geo;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.mongodb.core.query.Criteria.*;
|
||||
import static org.springframework.data.mongodb.core.query.Query.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.geo.Box;
|
||||
import org.springframework.data.geo.Circle;
|
||||
import org.springframework.data.geo.GeoResults;
|
||||
import org.springframework.data.geo.Metric;
|
||||
import org.springframework.data.geo.Metrics;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.geo.Polygon;
|
||||
import org.springframework.data.mongodb.config.AbstractIntegrationTests;
|
||||
import org.springframework.data.mongodb.core.CollectionCallback;
|
||||
import org.springframework.data.mongodb.core.IndexOperations;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.Venue;
|
||||
import org.springframework.data.mongodb.core.index.GeospatialIndex;
|
||||
import org.springframework.data.mongodb.core.index.IndexField;
|
||||
import org.springframework.data.mongodb.core.index.IndexInfo;
|
||||
import org.springframework.data.mongodb.core.query.NearQuery;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
|
||||
import com.mongodb.DBCollection;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.MongoException;
|
||||
import com.mongodb.WriteConcern;
|
||||
|
||||
/**
|
||||
* Modified from https://github.com/deftlabs/mongo-java-geospatial-example
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
public class GeoSpatialTests extends AbstractIntegrationTests {
|
||||
|
||||
private static final Log LOGGER = LogFactory.getLog(GeoSpatialTests.class);
|
||||
|
||||
@Autowired MongoTemplate template;
|
||||
|
||||
ExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
template.setWriteConcern(WriteConcern.FSYNC_SAFE);
|
||||
template.indexOps(Venue.class).ensureIndex(new GeospatialIndex("location"));
|
||||
|
||||
indexCreated();
|
||||
addVenues();
|
||||
}
|
||||
|
||||
private void addVenues() {
|
||||
|
||||
template.insert(new Venue("Penn Station", -73.99408, 40.75057));
|
||||
template.insert(new Venue("10gen Office", -73.99171, 40.738868));
|
||||
template.insert(new Venue("Flatiron Building", -73.988135, 40.741404));
|
||||
template.insert(new Venue("Players Club", -73.997812, 40.739128));
|
||||
template.insert(new Venue("City Bakery ", -73.992491, 40.738673));
|
||||
template.insert(new Venue("Splash Bar", -73.992491, 40.738673));
|
||||
template.insert(new Venue("Momofuku Milk Bar", -73.985839, 40.731698));
|
||||
template.insert(new Venue("Shake Shack", -73.98820, 40.74164));
|
||||
template.insert(new Venue("Penn Station", -73.99408, 40.75057));
|
||||
template.insert(new Venue("Empire State Building", -73.98602, 40.74894));
|
||||
// template.insert(new Venue("Washington Square Park", -73.99756, 40.73083));
|
||||
template.insert(new Venue("Ulaanbaatar, Mongolia", 106.9154, 47.9245));
|
||||
template.insert(new Venue("Maplewood, NJ", -74.2713, 40.73137));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void geoNear() {
|
||||
|
||||
NearQuery geoNear = NearQuery.near(-73, 40, Metrics.KILOMETERS).num(10).maxDistance(150);
|
||||
|
||||
GeoResults<Venue> result = template.geoNear(geoNear, Venue.class);
|
||||
|
||||
assertThat(result.getContent().size(), is(not(0)));
|
||||
assertThat(result.getAverageDistance().getMetric(), is((Metric) Metrics.KILOMETERS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withinCenter() {
|
||||
Circle circle = new Circle(-73.99171, 40.738868, 0.01);
|
||||
List<Venue> venues = template.find(query(where("location").within(circle)), Venue.class);
|
||||
assertThat(venues.size(), is(7));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withinCenterSphere() {
|
||||
Circle circle = new Circle(-73.99171, 40.738868, 0.003712240453784);
|
||||
List<Venue> venues = template.find(query(where("location").withinSphere(circle)), Venue.class);
|
||||
assertThat(venues.size(), is(11));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withinBox() {
|
||||
|
||||
Box box = new Box(new Point(-73.99756, 40.73083), new Point(-73.988135, 40.741404));
|
||||
List<Venue> venues = template.find(query(where("location").within(box)), Venue.class);
|
||||
assertThat(venues.size(), is(4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withinPolygon() {
|
||||
|
||||
Point first = new Point(-73.99756, 40.73083);
|
||||
Point second = new Point(-73.99756, 40.741404);
|
||||
Point third = new Point(-73.988135, 40.741404);
|
||||
Point fourth = new Point(-73.988135, 40.73083);
|
||||
|
||||
Polygon polygon = new Polygon(first, second, third, fourth);
|
||||
|
||||
List<Venue> venues = template.find(query(where("location").within(polygon)), Venue.class);
|
||||
assertThat(venues.size(), is(4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nearPoint() {
|
||||
Point point = new Point(-73.99171, 40.738868);
|
||||
List<Venue> venues = template.find(query(where("location").near(point).maxDistance(0.01)), Venue.class);
|
||||
assertThat(venues.size(), is(7));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nearSphere() {
|
||||
Point point = new Point(-73.99171, 40.738868);
|
||||
Query query = query(where("location").nearSphere(point).maxDistance(0.003712240453784));
|
||||
List<Venue> venues = template.find(query, Venue.class);
|
||||
assertThat(venues.size(), is(11));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchAllData() {
|
||||
|
||||
Venue foundVenue = template.findOne(query(where("name").is("Penn Station")), Venue.class);
|
||||
assertThat(foundVenue, is(notNullValue()));
|
||||
|
||||
List<Venue> venues = template.findAll(Venue.class);
|
||||
assertThat(venues.size(), is(12));
|
||||
|
||||
Collection<?> names = (Collection<?>) parser.parseExpression("![name]").getValue(venues);
|
||||
assertThat(names.size(), is(12));
|
||||
|
||||
}
|
||||
|
||||
public void indexCreated() {
|
||||
|
||||
List<DBObject> indexInfo = getIndexInfo(Venue.class);
|
||||
LOGGER.debug(indexInfo);
|
||||
|
||||
assertThat(indexInfo.size(), is(2));
|
||||
assertThat(indexInfo.get(1).get("name").toString(), is("location_2d"));
|
||||
assertThat(indexInfo.get(1).get("ns").toString(), is("database.newyork"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-360
|
||||
*/
|
||||
@Test
|
||||
public void indexInfoIsCorrect() {
|
||||
|
||||
IndexOperations operations = template.indexOps(Venue.class);
|
||||
List<IndexInfo> indexInfo = operations.getIndexInfo();
|
||||
|
||||
assertThat(indexInfo.size(), is(2));
|
||||
|
||||
List<IndexField> fields = indexInfo.get(0).getIndexFields();
|
||||
assertThat(fields.size(), is(1));
|
||||
assertThat(fields, hasItem(IndexField.create("_id", Direction.ASC)));
|
||||
|
||||
fields = indexInfo.get(1).getIndexFields();
|
||||
assertThat(fields.size(), is(1));
|
||||
assertThat(fields, hasItem(IndexField.geo("location")));
|
||||
}
|
||||
|
||||
// TODO move to MongoAdmin
|
||||
public List<DBObject> getIndexInfo(Class<?> clazz) {
|
||||
return template.execute(clazz, new CollectionCallback<List<DBObject>>() {
|
||||
|
||||
public List<DBObject> doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||
return collection.getIndexInfo();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.geo;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.mongodb.core.query.Criteria.*;
|
||||
import static org.springframework.data.mongodb.core.query.Query.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.geo.Box;
|
||||
import org.springframework.data.geo.Circle;
|
||||
import org.springframework.data.geo.GeoResults;
|
||||
import org.springframework.data.geo.Metric;
|
||||
import org.springframework.data.geo.Metrics;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.geo.Polygon;
|
||||
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.Venue;
|
||||
import org.springframework.data.mongodb.core.query.NearQuery;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.WriteConcern;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public abstract class AbstractGeoSpatialTests {
|
||||
|
||||
@Configuration
|
||||
static class TestConfig extends AbstractMongoConfiguration {
|
||||
|
||||
@Override
|
||||
protected String getDatabaseName() {
|
||||
return "database";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mongo mongo() throws Exception {
|
||||
return new MongoClient();
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired MongoTemplate template;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
template.setWriteConcern(WriteConcern.FSYNC_SAFE);
|
||||
|
||||
createIndex();
|
||||
addVenues();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
|
||||
dropIndex();
|
||||
removeVenues();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the index required to run the tests.
|
||||
*/
|
||||
protected abstract void createIndex();
|
||||
|
||||
/**
|
||||
* Remove index
|
||||
*/
|
||||
protected abstract void dropIndex();
|
||||
|
||||
protected void removeVenues() {
|
||||
template.dropCollection(Venue.class);
|
||||
}
|
||||
|
||||
protected void addVenues() {
|
||||
|
||||
template.insert(new Venue("Penn Station", -73.99408, 40.75057));
|
||||
template.insert(new Venue("10gen Office", -73.99171, 40.738868));
|
||||
template.insert(new Venue("Flatiron Building", -73.988135, 40.741404));
|
||||
template.insert(new Venue("Players Club", -73.997812, 40.739128));
|
||||
template.insert(new Venue("City Bakery ", -73.992491, 40.738673));
|
||||
template.insert(new Venue("Splash Bar", -73.992491, 40.738673));
|
||||
template.insert(new Venue("Momofuku Milk Bar", -73.985839, 40.731698));
|
||||
template.insert(new Venue("Shake Shack", -73.98820, 40.74164));
|
||||
template.insert(new Venue("Penn Station", -73.99408, 40.75057));
|
||||
template.insert(new Venue("Empire State Building", -73.98602, 40.74894));
|
||||
template.insert(new Venue("Ulaanbaatar, Mongolia", 106.9154, 47.9245));
|
||||
template.insert(new Venue("Maplewood, NJ", -74.2713, 40.73137));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void geoNear() {
|
||||
|
||||
NearQuery geoNear = NearQuery.near(-73, 40, Metrics.KILOMETERS).num(10).maxDistance(150);
|
||||
|
||||
GeoResults<Venue> result = template.geoNear(geoNear, Venue.class);
|
||||
|
||||
assertThat(result.getContent().size(), is(not(0)));
|
||||
assertThat(result.getAverageDistance().getMetric(), is((Metric) Metrics.KILOMETERS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withinCenter() {
|
||||
|
||||
Circle circle = new Circle(-73.99171, 40.738868, 0.01);
|
||||
List<Venue> venues = template.find(query(where("location").within(circle)), Venue.class);
|
||||
assertThat(venues.size(), is(7));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withinCenterSphere() {
|
||||
|
||||
Circle circle = new Circle(-73.99171, 40.738868, 0.003712240453784);
|
||||
List<Venue> venues = template.find(query(where("location").withinSphere(circle)), Venue.class);
|
||||
assertThat(venues.size(), is(11));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withinBox() {
|
||||
|
||||
Box box = new Box(new Point(-73.99756, 40.73083), new Point(-73.988135, 40.741404));
|
||||
List<Venue> venues = template.find(query(where("location").within(box)), Venue.class);
|
||||
assertThat(venues.size(), is(4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withinPolygon() {
|
||||
|
||||
Point first = new Point(-73.99756, 40.73083);
|
||||
Point second = new Point(-73.99756, 40.741404);
|
||||
Point third = new Point(-73.988135, 40.741404);
|
||||
Point fourth = new Point(-73.988135, 40.73083);
|
||||
|
||||
Polygon polygon = new Polygon(first, second, third, fourth);
|
||||
|
||||
List<Venue> venues = template.find(query(where("location").within(polygon)), Venue.class);
|
||||
assertThat(venues.size(), is(4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nearSphere() {
|
||||
Point point = new Point(-73.99171, 40.738868);
|
||||
Query query = query(where("location").nearSphere(point).maxDistance(0.003712240453784));
|
||||
List<Venue> venues = template.find(query, Venue.class);
|
||||
assertThat(venues.size(), is(11));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2010-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.mongodb.core.geo;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.mongodb.core.IndexOperations;
|
||||
import org.springframework.data.mongodb.core.Venue;
|
||||
import org.springframework.data.mongodb.core.index.GeoSpatialIndexType;
|
||||
import org.springframework.data.mongodb.core.index.GeospatialIndex;
|
||||
import org.springframework.data.mongodb.core.index.IndexField;
|
||||
import org.springframework.data.mongodb.core.index.IndexInfo;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class GeoSpatial2DSphereTests extends AbstractGeoSpatialTests {
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-360
|
||||
*/
|
||||
@Test
|
||||
public void indexInfoIsCorrect() {
|
||||
|
||||
IndexOperations operations = template.indexOps(Venue.class);
|
||||
List<IndexInfo> indexInfo = operations.getIndexInfo();
|
||||
|
||||
assertThat(indexInfo.size(), is(2));
|
||||
|
||||
List<IndexField> fields = indexInfo.get(0).getIndexFields();
|
||||
assertThat(fields.size(), is(1));
|
||||
assertThat(fields, hasItem(IndexField.create("_id", Direction.ASC)));
|
||||
|
||||
fields = indexInfo.get(1).getIndexFields();
|
||||
assertThat(fields.size(), is(1));
|
||||
assertThat(fields, hasItem(IndexField.geo("location")));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createIndex() {
|
||||
template.indexOps(Venue.class).ensureIndex(new GeospatialIndex("location").typed(GeoSpatialIndexType.GEO_2DSPHERE));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dropIndex() {
|
||||
template.indexOps(Venue.class).dropIndex("location_2dsphere");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2010-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.mongodb.core.geo;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.mongodb.core.query.Criteria.*;
|
||||
import static org.springframework.data.mongodb.core.query.Query.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.mongodb.core.IndexOperations;
|
||||
import org.springframework.data.mongodb.core.Venue;
|
||||
import org.springframework.data.mongodb.core.index.GeoSpatialIndexType;
|
||||
import org.springframework.data.mongodb.core.index.GeospatialIndex;
|
||||
import org.springframework.data.mongodb.core.index.IndexField;
|
||||
import org.springframework.data.mongodb.core.index.IndexInfo;
|
||||
|
||||
/**
|
||||
* Modified from https://github.com/deftlabs/mongo-java-geospatial-example
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class GeoSpatial2DTests extends AbstractGeoSpatialTests {
|
||||
|
||||
@Test
|
||||
public void nearPoint() {
|
||||
Point point = new Point(-73.99171, 40.738868);
|
||||
List<Venue> venues = template.find(query(where("location").near(point).maxDistance(0.01)), Venue.class);
|
||||
assertThat(venues.size(), is(7));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-360
|
||||
*/
|
||||
@Test
|
||||
public void indexInfoIsCorrect() {
|
||||
|
||||
IndexOperations operations = template.indexOps(Venue.class);
|
||||
List<IndexInfo> indexInfo = operations.getIndexInfo();
|
||||
|
||||
assertThat(indexInfo.size(), is(2));
|
||||
|
||||
List<IndexField> fields = indexInfo.get(0).getIndexFields();
|
||||
assertThat(fields.size(), is(1));
|
||||
assertThat(fields, hasItem(IndexField.create("_id", Direction.ASC)));
|
||||
|
||||
fields = indexInfo.get(1).getIndexFields();
|
||||
assertThat(fields.size(), is(1));
|
||||
assertThat(fields, hasItem(IndexField.geo("location")));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createIndex() {
|
||||
template.indexOps(Venue.class).ensureIndex(new GeospatialIndex("location").typed(GeoSpatialIndexType.GEO_2D));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dropIndex() {
|
||||
template.indexOps(Venue.class).dropIndex("location_2d");
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,6 +39,8 @@ import org.mockito.stubbing.Answer;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.Metrics;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.geo.Polygon;
|
||||
import org.springframework.data.geo.Shape;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mongodb.core.Person;
|
||||
import org.springframework.data.mongodb.core.Venue;
|
||||
@@ -483,6 +485,24 @@ public class MongoQueryCreatorUnitTests {
|
||||
assertThat(query, is(query(where("location").near(point).maxDistance(1.0))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1136
|
||||
*/
|
||||
@Test
|
||||
public void shouldCreateWithinQueryCorrectly() {
|
||||
|
||||
Point first = new Point(1, 1);
|
||||
Point second = new Point(2, 2);
|
||||
Point third = new Point(3, 3);
|
||||
Shape shape = new Polygon(first, second, third);
|
||||
|
||||
PartTree tree = new PartTree("findByAddress_GeoWithin", User.class);
|
||||
MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, shape), context);
|
||||
Query query = creator.createQuery();
|
||||
|
||||
assertThat(query, is(query(where("address.geo").within(shape))));
|
||||
}
|
||||
|
||||
interface PersonRepository extends Repository<Person, Long> {
|
||||
|
||||
List<Person> findByLocationNearAndFirstname(Point location, Distance maxDistance, String firstname);
|
||||
@@ -495,5 +515,13 @@ public class MongoQueryCreatorUnitTests {
|
||||
@DBRef User creator;
|
||||
|
||||
List<String> emailAddresses;
|
||||
|
||||
Address address;
|
||||
}
|
||||
|
||||
static class Address {
|
||||
|
||||
String street;
|
||||
Point geo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ The jumping off ground for learning about MongoDB is http://www.mongodb.org/[www
|
||||
|
||||
Spring Data MongoDB 1.x binaries requires JDK level 6.0 and above, and http://spring.io/docs[Spring Framework] 3.2.x and above.
|
||||
|
||||
In terms of document stores, http://www.mongodb.org/[MongoDB] preferably version 2.4.
|
||||
In terms of document stores, http://www.mongodb.org/[MongoDB] at least 2.4, preferably version 2.6.
|
||||
|
||||
== Additional Help Resources
|
||||
|
||||
|
||||
@@ -212,11 +212,11 @@ NOTE: Note that for version 1.0 we currently don't support referring to paramete
|
||||
|
||||
| `Within`
|
||||
| `findByLocationWithin(Circle circle)`
|
||||
| `{"location" : {"$within" : {"$center" : [ [x, y], distance]}}}`
|
||||
| `{"location" : {"$geoWithin" : {"$center" : [ [x, y], distance]}}}`
|
||||
|
||||
| `Within`
|
||||
| `findByLocationWithin(Box box)`
|
||||
| `{"location" : {"$within" : {"$box" : [ [x1, y1], x2, y2]}}}True`
|
||||
| `{"location" : {"$geoWithin" : {"$box" : [ [x1, y1], x2, y2]}}}`
|
||||
|
||||
| `IsTrue, True`
|
||||
| `findByActiveIsTrue()`
|
||||
|
||||
@@ -1041,9 +1041,9 @@ As you can see most methods return the `Criteria` object to provide a fluent sty
|
||||
|
||||
There are also methods on the Criteria class for geospatial queries. Here is a listing but look at the section on <<mongo.geospatial,GeoSpatial Queries>> to see them in action.
|
||||
|
||||
* `Criteria` *withinCenter* `(Circle circle)` Creates a geospatial criterion using `$within $center` operators
|
||||
* `Criteria` *withinCenterSphere* `(Circle circle)` Creates a geospatial criterion using `$within $center` operators. This is only available for MongoDB 1.7 and higher.
|
||||
* `Criteria` *withinBox* `(Box box)` Creates a geospatial criterion using a `$within $box` operation ``
|
||||
* `Criteria` *within* `(Circle circle)` Creates a geospatial criterion using `$geoWithin $center` operators.
|
||||
* `Criteria` *within* `(Box box)` Creates a geospatial criterion using a `$geoWithin $box` operation.
|
||||
* `Criteria` *withinSphere* `(Circle circle)` Creates a geospatial criterion using `$geoWithin $center` operators.
|
||||
* `Criteria` *near* `(Point point)` Creates a geospatial criterion using a `$near `operation
|
||||
* `Criteria` *nearSphere* `(Point point)` Creates a geospatial criterion using `$nearSphere$center` operations. This is only available for MongoDB 1.7 and higher.
|
||||
* `Criteria` *maxDistance* `(double maxDistance)` Creates a geospatial criterion using the `$maxDistance` operation, for use with $near.
|
||||
@@ -1073,7 +1073,7 @@ The query methods need to specify the target type T that will be returned and th
|
||||
[[mongo.geospatial]]
|
||||
=== GeoSpatial Queries
|
||||
|
||||
MongoDB supports GeoSpatial queries through the use of operators such as `$near`, `$within`, and `$nearSphere`. Methods specific to geospatial queries are available on the `Criteria` class. There are also a few shape classes, `Box`, `Circle`, and `Point` that are used in conjunction with geospatial related `Criteria` methods.
|
||||
MongoDB supports GeoSpatial queries through the use of operators such as `$near`, `$within`, `geoWithin` and `$nearSphere`. Methods specific to geospatial queries are available on the `Criteria` class. There are also a few shape classes, `Box`, `Circle`, and `Point` that are used in conjunction with geospatial related `Criteria` methods.
|
||||
|
||||
To understand how to perform GeoSpatial queries we will use the following Venue class taken from the integration tests.which relies on using the rich `MappingMongoConverter`.
|
||||
|
||||
@@ -1122,7 +1122,7 @@ To find locations within a `Circle`, the following query can be used.
|
||||
----
|
||||
Circle circle = new Circle(-73.99171, 40.738868, 0.01);
|
||||
List<Venue> venues =
|
||||
template.find(new Query(Criteria.where("location").withinCenter(circle)), Venue.class);
|
||||
template.find(new Query(Criteria.where("location").within(circle)), Venue.class);
|
||||
----
|
||||
|
||||
To find venues within a `Circle` using spherical coordinates the following query can be used
|
||||
@@ -1131,7 +1131,7 @@ To find venues within a `Circle` using spherical coordinates the following query
|
||||
----
|
||||
Circle circle = new Circle(-73.99171, 40.738868, 0.003712240453784);
|
||||
List<Venue> venues =
|
||||
template.find(new Query(Criteria.where("location").withinCenterSphere(circle)), Venue.class);
|
||||
template.find(new Query(Criteria.where("location").withinSphere(circle)), Venue.class);
|
||||
----
|
||||
|
||||
To find venues within a `Box` the following query can be used
|
||||
@@ -1141,7 +1141,7 @@ To find venues within a `Box` the following query can be used
|
||||
//lower-left then upper-right
|
||||
Box box = new Box(new Point(-73.99756, 40.73083), new Point(-73.988135, 40.741404));
|
||||
List<Venue> venues =
|
||||
template.find(new Query(Criteria.where("location").withinBox(box)), Venue.class);
|
||||
template.find(new Query(Criteria.where("location").within(box)), Venue.class);
|
||||
----
|
||||
|
||||
To find venues near a `Point`, the following query can be used
|
||||
|
||||
Reference in New Issue
Block a user