package org.mongodb.morphia.geo; import com.mongodb.DBObject; import com.mongodb.MongoException; import org.junit.Test; import org.mongodb.morphia.TestBase; import org.mongodb.morphia.query.Query; import java.util.List; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.assertThat; import static org.mongodb.morphia.testutil.IndexMatcher.doesNotHaveIndexNamed; import static org.mongodb.morphia.testutil.IndexMatcher.hasIndexNamed; import static org.mongodb.morphia.testutil.JSONMatcher.jsonEqual; /** * This test shows how to define an entity that uses the legacy co-ordinate pairs standard, which works with MongoDB server versions 2.2 * and * earlier. If you are using a server version higher than 2.2 (i.e. 2.4 and onwards) you should store location information as <a * href="http://docs.mongodb.org/manual/reference/glossary/#term-geojson">GeoJSON</a> and consult the documentation for indexes and queries * that work on this format. Storing the location as GeoJSON gives you access to a wider range of queries. * <p/> * This set of tests should run on all server versions. */ public class LegacyCoordsTest extends TestBase { @Test public void shouldCreateA2dIndexOnAnEntityWithArrayOfCoordinates() { // given PlaceWithLegacyCoords pointA = new PlaceWithLegacyCoords(new double[]{3.1, 5.2}, "Point A"); getDs().save(pointA); // when getDs().ensureIndexes(); // then List<DBObject> indexes = getDs().getCollection(PlaceWithLegacyCoords.class).getIndexInfo(); assertThat(indexes, hasIndexNamed("location_2d")); } @Test public void shouldFindPointWithExactMatch() { // given final PlaceWithLegacyCoords nearbyPlace = new PlaceWithLegacyCoords(new double[]{1.1, 2.3}, "Nearby Place"); getDs().save(nearbyPlace); getDs().ensureIndexes(); // when List<PlaceWithLegacyCoords> found = getDs().find(PlaceWithLegacyCoords.class) .field("location") .equal(new double[]{1.1, 2.3}) .asList(); // then assertThat(found, is(notNullValue())); assertThat(found.size(), is(1)); assertThat(found.get(0), is(nearbyPlace)); } @Test @SuppressWarnings("deprecation") public void shouldGenerateCorrectQueryForNearSphereWithRadius() { // when Query<PlaceWithLegacyCoords> query = getDs().find(PlaceWithLegacyCoords.class) .field("location") .near(42.08563, -87.99822, 2, true); // then assertThat(query.getQueryObject().toString(), jsonEqual("{ \"location\" : " + "{ \"$nearSphere\" : [ 42.08563 , -87.99822] , " + "\"$maxDistance\" : 2.0}}")); } @Test @SuppressWarnings("deprecation") public void shouldGenerateCorrectQueryForNearWithMaxDistance() { // when Query<PlaceWithLegacyCoords> query = getDs().find(PlaceWithLegacyCoords.class) .field("location") .near(42.08563, -87.99822, 2); // then assertThat(query.getQueryObject().toString(), jsonEqual("{ \"location\" : " + "{ \"$near\" : [ 42.08563 , -87.99822] , " + "\"$maxDistance\" : 2.0}}")); } @Test public void shouldNotReturnAnyResultsIfNoLocationsWithinGivenRadius() throws Exception { // given final PlaceWithLegacyCoords nearbyPlace = new PlaceWithLegacyCoords(new double[]{1.1, 2.3}, "Nearby Place"); getDs().save(nearbyPlace); getDs().ensureIndexes(); // when Query<PlaceWithLegacyCoords> locationQuery = getDs().find(PlaceWithLegacyCoords.class) .field("location") .near(1.0, 2.0, 0.1); // then assertThat(locationQuery.asList().size(), is(0)); assertThat(locationQuery.get(), is(nullValue())); } @Test public void shouldReturnAllLocationsOrderedByDistanceFromQueryLocationWhenPerformingNearQuery() throws Exception { // given final PlaceWithLegacyCoords nearbyPlace = new PlaceWithLegacyCoords(new double[]{1.1, 2.3}, "Nearby Place"); getDs().save(nearbyPlace); final PlaceWithLegacyCoords furtherAwayPlace = new PlaceWithLegacyCoords(new double[]{10.1, 12.3}, "Further Away Place"); getDs().save(furtherAwayPlace); getDs().ensureIndexes(); // when final List<PlaceWithLegacyCoords> found = getDs().find(PlaceWithLegacyCoords.class) .field("location") .near(1.0, 2.0) .asList(); // then assertThat(found, is(notNullValue())); assertThat(found.size(), is(2)); assertThat(found.get(0), is(nearbyPlace)); assertThat(found.get(1), is(furtherAwayPlace)); } @Test public void shouldReturnOnlyThosePlacesWithinTheGivenRadius() throws Exception { // given final PlaceWithLegacyCoords nearbyPlace = new PlaceWithLegacyCoords(new double[]{1.1, 2.3}, "Nearby Place"); getDs().save(nearbyPlace); final PlaceWithLegacyCoords furtherAwayPlace = new PlaceWithLegacyCoords(new double[]{10.1, 12.3}, "Further Away Place"); getDs().save(furtherAwayPlace); getDs().ensureIndexes(); // when final List<PlaceWithLegacyCoords> found = getDs().find(PlaceWithLegacyCoords.class) .field("location") .near(1.0, 2.0, 1.5) .asList(); // then assertThat(found, is(notNullValue())); assertThat(found.size(), is(1)); assertThat(found.get(0), is(nearbyPlace)); } @Test(expected = MongoException.class) public void shouldThrowAnExceptionIfQueryingWithoutA2dIndex() throws Exception { // given final PlaceWithLegacyCoords nearbyPlace = new PlaceWithLegacyCoords(new double[]{1.1, 2.3}, "Nearby Place"); getDs().save(nearbyPlace); List<DBObject> indexes = getDs().getCollection(PlaceWithLegacyCoords.class).getIndexInfo(); assertThat(indexes, doesNotHaveIndexNamed("location_2d")); // when getDs().find(PlaceWithLegacyCoords.class) .field("location") .near(0, 0) .get(); // then expect the Exception } }