Browse Source

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.
pull/265/head
Christoph Strobl 11 years ago committed by Oliver Gierke
parent
commit
59e54cecd2
  1. 12
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Criteria.java
  2. 41
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/GeoCommand.java
  3. 392
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/geo/AbstractGeoSpatialTests.java
  4. 68
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/geo/GeoSpatial2DSphereTests.java
  5. 82
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/geo/GeoSpatial2DTests.java
  6. 30
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java
  7. 2
      src/main/asciidoc/preface.adoc
  8. 4
      src/main/asciidoc/reference/mongo-repositories.adoc
  9. 14
      src/main/asciidoc/reference/mongodb.adoc

12
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Criteria.java

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 * Creates a geospatial criterion using a {@literal $geoWithin $centerSphere} operation. This is only available for
* 1.7 and higher. * Mongo 2.4 and higher.
* *
* @see http://docs.mongodb.org/manual/reference/operator/query/geoWithin/ * @see http://docs.mongodb.org/manual/reference/operator/query/geoWithin/
* @see http://docs.mongodb.org/manual/reference/operator/query/centerSphere/ * @see http://docs.mongodb.org/manual/reference/operator/query/centerSphere/
@ -386,12 +386,12 @@ public class Criteria implements CriteriaDefinition {
*/ */
public Criteria withinSphere(Circle circle) { public Criteria withinSphere(Circle circle) {
Assert.notNull(circle); Assert.notNull(circle);
criteria.put("$within", new GeoCommand(new Sphere(circle))); criteria.put("$geoWithin", new GeoCommand(new Sphere(circle)));
return this; 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/ * @see http://docs.mongodb.org/manual/reference/operator/query/geoWithin/
* @param shape * @param shape
@ -400,7 +400,7 @@ public class Criteria implements CriteriaDefinition {
public Criteria within(Shape shape) { public Criteria within(Shape shape) {
Assert.notNull(shape); Assert.notNull(shape);
criteria.put("$within", new GeoCommand(shape)); criteria.put("$geoWithin", new GeoCommand(shape));
return this; return this;
} }

41
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/GeoCommand.java

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.geo.Shape;
import org.springframework.data.mongodb.core.geo.Sphere; import org.springframework.data.mongodb.core.geo.Sphere;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/** /**
* Wrapper around a {@link Shape} to allow appropriate query rendering. * Wrapper around a {@link Shape} to allow appropriate query rendering.
* *
* @author Thomas Darimont * @author Thomas Darimont
* @author Christoph Strobl
* @since 1.5 * @since 1.5
*/ */
public class GeoCommand { public class GeoCommand {
@ -82,4 +84,41 @@ public class GeoCommand {
throw new IllegalArgumentException("Unknown shape: " + shape); 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);
}
} }

392
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/geo/GeoSpatialTests.java → spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/geo/AbstractGeoSpatialTests.java

@ -1,216 +1,176 @@
/* /*
* Copyright 2010-2014 the original author or authors. * Copyright 2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.data.mongodb.core.geo;
package org.springframework.data.mongodb.core.geo;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.*; import static org.junit.Assert.*;
import static org.junit.Assert.*; import static org.springframework.data.mongodb.core.query.Criteria.*;
import static org.springframework.data.mongodb.core.query.Criteria.*; import static org.springframework.data.mongodb.core.query.Query.*;
import static org.springframework.data.mongodb.core.query.Query.*;
import java.util.List;
import java.util.Collection;
import java.util.List; import org.junit.After;
import org.junit.Before;
import org.apache.commons.logging.Log; import org.junit.Test;
import org.apache.commons.logging.LogFactory; import org.junit.runner.RunWith;
import org.junit.Before; import org.springframework.beans.factory.annotation.Autowired;
import org.junit.Test; import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.geo.Box;
import org.springframework.dao.DataAccessException; import org.springframework.data.geo.Circle;
import org.springframework.data.domain.Sort.Direction; import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Box; import org.springframework.data.geo.Metric;
import org.springframework.data.geo.Circle; import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.GeoResults; import org.springframework.data.geo.Point;
import org.springframework.data.geo.Metric; import org.springframework.data.geo.Polygon;
import org.springframework.data.geo.Metrics; import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
import org.springframework.data.geo.Point; import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.geo.Polygon; import org.springframework.data.mongodb.core.Venue;
import org.springframework.data.mongodb.config.AbstractIntegrationTests; import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.CollectionCallback; import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.IndexOperations; import org.springframework.test.context.ContextConfiguration;
import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.data.mongodb.core.Venue;
import org.springframework.data.mongodb.core.index.GeospatialIndex; import com.mongodb.Mongo;
import org.springframework.data.mongodb.core.index.IndexField; import com.mongodb.MongoClient;
import org.springframework.data.mongodb.core.index.IndexInfo; import com.mongodb.WriteConcern;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query; /**
import org.springframework.expression.ExpressionParser; * @author Christoph Strobl
import org.springframework.expression.spel.standard.SpelExpressionParser; */
@RunWith(SpringJUnit4ClassRunner.class)
import com.mongodb.DBCollection; @ContextConfiguration
import com.mongodb.DBObject; public abstract class AbstractGeoSpatialTests {
import com.mongodb.MongoException;
import com.mongodb.WriteConcern; @Configuration
static class TestConfig extends AbstractMongoConfiguration {
/**
* Modified from https://github.com/deftlabs/mongo-java-geospatial-example @Override
* protected String getDatabaseName() {
* @author Mark Pollack return "database";
* @author Oliver Gierke }
* @author Thomas Darimont
*/ @Override
public class GeoSpatialTests extends AbstractIntegrationTests { public Mongo mongo() throws Exception {
return new MongoClient();
private static final Log LOGGER = LogFactory.getLog(GeoSpatialTests.class); }
}
@Autowired MongoTemplate template;
@Autowired MongoTemplate template;
ExpressionParser parser = new SpelExpressionParser();
@Before
@Before public void setUp() {
public void setUp() throws Exception {
template.setWriteConcern(WriteConcern.FSYNC_SAFE);
template.setWriteConcern(WriteConcern.FSYNC_SAFE);
template.indexOps(Venue.class).ensureIndex(new GeospatialIndex("location")); createIndex();
addVenues();
indexCreated(); }
addVenues();
} @After
public void tearDown() {
private void addVenues() {
dropIndex();
template.insert(new Venue("Penn Station", -73.99408, 40.75057)); removeVenues();
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)); * Create the index required to run the tests.
template.insert(new Venue("Splash Bar", -73.992491, 40.738673)); */
template.insert(new Venue("Momofuku Milk Bar", -73.985839, 40.731698)); protected abstract void createIndex();
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)); * Remove index
// template.insert(new Venue("Washington Square Park", -73.99756, 40.73083)); */
template.insert(new Venue("Ulaanbaatar, Mongolia", 106.9154, 47.9245)); protected abstract void dropIndex();
template.insert(new Venue("Maplewood, NJ", -74.2713, 40.73137));
} protected void removeVenues() {
template.dropCollection(Venue.class);
@Test }
public void geoNear() {
protected void addVenues() {
NearQuery geoNear = NearQuery.near(-73, 40, Metrics.KILOMETERS).num(10).maxDistance(150);
template.insert(new Venue("Penn Station", -73.99408, 40.75057));
GeoResults<Venue> result = template.geoNear(geoNear, Venue.class); template.insert(new Venue("10gen Office", -73.99171, 40.738868));
template.insert(new Venue("Flatiron Building", -73.988135, 40.741404));
assertThat(result.getContent().size(), is(not(0))); template.insert(new Venue("Players Club", -73.997812, 40.739128));
assertThat(result.getAverageDistance().getMetric(), is((Metric) Metrics.KILOMETERS)); 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));
@Test template.insert(new Venue("Shake Shack", -73.98820, 40.74164));
public void withinCenter() { template.insert(new Venue("Penn Station", -73.99408, 40.75057));
Circle circle = new Circle(-73.99171, 40.738868, 0.01); template.insert(new Venue("Empire State Building", -73.98602, 40.74894));
List<Venue> venues = template.find(query(where("location").within(circle)), Venue.class); template.insert(new Venue("Ulaanbaatar, Mongolia", 106.9154, 47.9245));
assertThat(venues.size(), is(7)); template.insert(new Venue("Maplewood, NJ", -74.2713, 40.73137));
} }
@Test @Test
public void withinCenterSphere() { public void geoNear() {
Circle circle = new Circle(-73.99171, 40.738868, 0.003712240453784);
List<Venue> venues = template.find(query(where("location").withinSphere(circle)), Venue.class); NearQuery geoNear = NearQuery.near(-73, 40, Metrics.KILOMETERS).num(10).maxDistance(150);
assertThat(venues.size(), is(11));
} GeoResults<Venue> result = template.geoNear(geoNear, Venue.class);
@Test assertThat(result.getContent().size(), is(not(0)));
public void withinBox() { assertThat(result.getAverageDistance().getMetric(), is((Metric) Metrics.KILOMETERS));
}
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); @Test
assertThat(venues.size(), is(4)); public void withinCenter() {
}
Circle circle = new Circle(-73.99171, 40.738868, 0.01);
@Test List<Venue> venues = template.find(query(where("location").within(circle)), Venue.class);
public void withinPolygon() { assertThat(venues.size(), is(7));
}
Point first = new Point(-73.99756, 40.73083);
Point second = new Point(-73.99756, 40.741404); @Test
Point third = new Point(-73.988135, 40.741404); public void withinCenterSphere() {
Point fourth = new Point(-73.988135, 40.73083);
Circle circle = new Circle(-73.99171, 40.738868, 0.003712240453784);
Polygon polygon = new Polygon(first, second, third, fourth); List<Venue> venues = template.find(query(where("location").withinSphere(circle)), Venue.class);
assertThat(venues.size(), is(11));
List<Venue> venues = template.find(query(where("location").within(polygon)), Venue.class); }
assertThat(venues.size(), is(4));
} @Test
public void withinBox() {
@Test
public void nearPoint() { Box box = new Box(new Point(-73.99756, 40.73083), new Point(-73.988135, 40.741404));
Point point = new Point(-73.99171, 40.738868); List<Venue> venues = template.find(query(where("location").within(box)), Venue.class);
List<Venue> venues = template.find(query(where("location").near(point).maxDistance(0.01)), Venue.class); assertThat(venues.size(), is(4));
assertThat(venues.size(), is(7)); }
}
@Test
@Test public void withinPolygon() {
public void nearSphere() {
Point point = new Point(-73.99171, 40.738868); Point first = new Point(-73.99756, 40.73083);
Query query = query(where("location").nearSphere(point).maxDistance(0.003712240453784)); Point second = new Point(-73.99756, 40.741404);
List<Venue> venues = template.find(query, Venue.class); Point third = new Point(-73.988135, 40.741404);
assertThat(venues.size(), is(11)); Point fourth = new Point(-73.988135, 40.73083);
}
Polygon polygon = new Polygon(first, second, third, fourth);
@Test
public void searchAllData() { List<Venue> venues = template.find(query(where("location").within(polygon)), Venue.class);
assertThat(venues.size(), is(4));
Venue foundVenue = template.findOne(query(where("name").is("Penn Station")), Venue.class); }
assertThat(foundVenue, is(notNullValue()));
@Test
List<Venue> venues = template.findAll(Venue.class); public void nearSphere() {
assertThat(venues.size(), is(12)); Point point = new Point(-73.99171, 40.738868);
Query query = query(where("location").nearSphere(point).maxDistance(0.003712240453784));
Collection<?> names = (Collection<?>) parser.parseExpression("![name]").getValue(venues); List<Venue> venues = template.find(query, Venue.class);
assertThat(names.size(), is(12)); assertThat(venues.size(), is(11));
}
}
}
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();
}
});
}
}

68
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/geo/GeoSpatial2DSphereTests.java

@ -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");
}
}

82
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/geo/GeoSpatial2DTests.java

@ -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");
}
}

30
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.Distance;
import org.springframework.data.geo.Metrics; import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.Point; 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.mapping.context.MappingContext;
import org.springframework.data.mongodb.core.Person; import org.springframework.data.mongodb.core.Person;
import org.springframework.data.mongodb.core.Venue; 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)))); 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> { interface PersonRepository extends Repository<Person, Long> {
List<Person> findByLocationNearAndFirstname(Point location, Distance maxDistance, String firstname); List<Person> findByLocationNearAndFirstname(Point location, Distance maxDistance, String firstname);
@ -495,5 +515,13 @@ public class MongoQueryCreatorUnitTests {
@DBRef User creator; @DBRef User creator;
List<String> emailAddresses; List<String> emailAddresses;
Address address;
}
static class Address {
String street;
Point geo;
} }
} }

2
src/main/asciidoc/preface.adoc

@ -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. 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 == Additional Help Resources

4
src/main/asciidoc/reference/mongo-repositories.adoc

@ -212,11 +212,11 @@ NOTE: Note that for version 1.0 we currently don't support referring to paramete
| `Within` | `Within`
| `findByLocationWithin(Circle circle)` | `findByLocationWithin(Circle circle)`
| `{"location" : {"$within" : {"$center" : [ [x, y], distance]}}}` | `{"location" : {"$geoWithin" : {"$center" : [ [x, y], distance]}}}`
| `Within` | `Within`
| `findByLocationWithin(Box box)` | `findByLocationWithin(Box box)`
| `{"location" : {"$within" : {"$box" : [ [x1, y1], x2, y2]}}}True` | `{"location" : {"$geoWithin" : {"$box" : [ [x1, y1], x2, y2]}}}`
| `IsTrue, True` | `IsTrue, True`
| `findByActiveIsTrue()` | `findByActiveIsTrue()`

14
src/main/asciidoc/reference/mongodb.adoc

@ -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. 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` *within* `(Circle circle)` Creates a geospatial criterion using `$geoWithin $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` *within* `(Box box)` Creates a geospatial criterion using a `$geoWithin $box` operation.
* `Criteria` *withinBox* `(Box box)` Creates a geospatial criterion using a `$within $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` *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` *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. * `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]] [[mongo.geospatial]]
=== GeoSpatial Queries === 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`. 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); Circle circle = new Circle(-73.99171, 40.738868, 0.01);
List<Venue> venues = 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 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); Circle circle = new Circle(-73.99171, 40.738868, 0.003712240453784);
List<Venue> venues = 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 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 //lower-left then upper-right
Box box = new Box(new Point(-73.99756, 40.73083), new Point(-73.988135, 40.741404)); Box box = new Box(new Point(-73.99756, 40.73083), new Point(-73.988135, 40.741404));
List<Venue> venues = 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 To find venues near a `Point`, the following query can be used

Loading…
Cancel
Save