DATAMONGO-2059 - Replace usage of deprecated collection.count() with collection.countDocuments().

This commit switches from simple collection.count(), operating on potentially false collection statistic,  to countDocuments() using an aggregation for accurate results.
The transition required query modifications at some points because $match does not support $near and $nearSphere but require $geoWithin along with $center or $centerSphere which does not support $minDistance (see https://jira.mongodb.org/browse/SERVER-37043).
$geoWithin further more does not sort results by distance, but this fact can be ignored when just counting matches.

Examples:

{ location : { $near : [-73.99171, 40.738868], $maxDistance : 1.1 } }
{ location : { $geoWithin : { $center: [ [-73.99171, 40.738868], 1.1] } } }

{ location : { $near : [-73.99171, 40.738868], $minDistance : 0.1, $maxDistance : 1.1 } }
{$and :[ { $nor :[ { location :{ $geoWithin :{ $center :[ [-73.99171, 40.738868 ], 0.01] } } } ]}, { location :{ $geoWithin :{ $center :[ [-73.99171, 40.738868 ], 1.1] } } } ] }

Original pull request: #604.
This commit is contained in:
Christoph Strobl
2019-09-26 13:00:14 +02:00
committed by Mark Paluch
parent 4a04e82e86
commit 909c51d00a
13 changed files with 243 additions and 69 deletions

View File

@@ -53,6 +53,7 @@ import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Metric;
import org.springframework.data.geo.Point;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.mapping.PropertyReferenceException;
import org.springframework.data.mapping.callback.EntityCallbacks;
@@ -1191,11 +1192,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
LOGGER.debug("Executing count: {} in collection: {}", serializeToJsonSafely(filter), collectionName);
}
if (MongoDatabaseUtils.isTransactionActive(getMongoDbFactory())) {
return execute(collectionName, collection -> collection.countDocuments(filter, options));
}
return execute(collectionName, collection -> collection.count(filter, options));
return execute(collectionName, collection -> collection.countDocuments(QueryMapper.processCountFilter(filter), options));
}
/*
@@ -3523,19 +3520,5 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
// native MongoDB objects that offer methods with ClientSession must not be proxied.
return delegate.getDb();
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.MongoTemplate#doCount(java.lang.String, org.bson.Document, com.mongodb.client.model.CountOptions)
*/
@Override
protected long doCount(String collectionName, Document filter, CountOptions options) {
if (!session.hasActiveTransaction()) {
return super.doCount(collectionName, filter, options);
}
return execute(collectionName, collection -> collection.countDocuments(filter, options));
}
}
}

View File

@@ -1300,9 +1300,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
*/
protected Mono<Long> doCount(String collectionName, Document filter, CountOptions options) {
return ReactiveMongoDatabaseUtils.isTransactionActive(mongoDatabaseFactory) //
.flatMap(txActive -> createMono(collectionName,
collection -> txActive ? collection.countDocuments(filter, options) : collection.count(filter, options)));
return createMono(collectionName,
collection -> collection.countDocuments(QueryMapper.processCountFilter(filter), options));
}
/*
@@ -3323,20 +3322,6 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
// native MongoDB objects that offer methods with ClientSession must not be proxied.
return delegate.getMongoDatabase();
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.ReactiveMongoTemplate#count(java.lang.String, org.bson.Document, com.mongodb.client.model.CountOptions)
*/
@Override
public Mono<Long> doCount(String collectionName, Document filter, CountOptions options) {
if (!session.hasActiveTransaction()) {
return super.doCount(collectionName, filter, options);
}
return createMono(collectionName, collection -> collection.countDocuments(filter, options));
}
}
@RequiredArgsConstructor

View File

@@ -15,17 +15,8 @@
*/
package org.springframework.data.mongodb.core.convert;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -36,6 +27,7 @@ import org.bson.types.ObjectId;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.domain.Example;
import org.springframework.data.geo.Point;
import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.MappingException;
import org.springframework.data.mapping.PersistentEntity;
@@ -1290,4 +1282,97 @@ public class QueryMapper {
public MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> getMappingContext() {
return mappingContext;
}
public static Document processCountFilter(Document source) {
Document target = new Document();
for (Entry<String, Object> entry : source.entrySet()) {
if (entry.getValue() instanceof Document) {
Document theValue = (Document) entry.getValue();
if (containsNear(theValue)) {
target.putAll(createGeoWithin(entry.getKey(), theValue));
} else {
target.put(entry.getKey(), entry.getValue());
}
} else if (entry.getValue() instanceof Collection) {
Collection<Object> tmp = new ArrayList<>();
for (Object val : (Collection) entry.getValue()) {
if (val instanceof Document) {
tmp.add(processCountFilter((Document) val));
} else {
tmp.add(val);
}
}
target.put(entry.getKey(), tmp);
} else {
target.put(entry.getKey(), entry.getValue());
}
}
return target;
}
private static Document createGeoWithin(String key, Document source) {
boolean spheric = source.containsKey("$nearSphere");
Object $near = spheric ? source.get("$nearSphere") : source.get("$near");
Number maxDistance = source.containsKey("$maxDistance") ? (Number) source.get("$maxDistance") : Double.MAX_VALUE;
List<Object> $centerMax = Arrays.asList(toCenterCoordinates($near), maxDistance);
Document $geoWithinMax = new Document("$geoWithin",
new Document(spheric ? "$centerSphere" : "$center", $centerMax));
if (!containsNearWithMinDistance(source)) {
return new Document(key, $geoWithinMax);
}
Number minDistance = (Number) source.get("$minDistance");
List<Object> $centerMin = Arrays.asList(toCenterCoordinates($near), minDistance);
Document $geoWithinMin = new Document("$geoWithin",
new Document(spheric ? "$centerSphere" : "$center", $centerMin));
List<Document> criteria = new ArrayList<>();
criteria.add(new Document("$nor", Arrays.asList(new Document(key, $geoWithinMin))));
criteria.add(new Document(key, $geoWithinMax));
return new Document("$and", criteria);
}
private static boolean containsNear(Document source) {
if (source.containsKey("$near") || source.containsKey("$nearSphere")) {
return true;
}
return false;
}
private static boolean containsNearWithMinDistance(Document source) {
if (!containsNear(source)) {
return false;
}
return source.containsKey("$minDistance");
}
private static Object toCenterCoordinates(Object value) {
if (ObjectUtils.isArray(value)) {
return value;
}
if (value instanceof Point) {
return Arrays.asList(((Point) value).getX(), ((Point) value).getY());
}
if (value instanceof Document && ((Document) value).containsKey("x")) {
Document point = (Document) value;
return Arrays.asList(point.get("x"), point.get("y"));
}
return value;
}
}

View File

@@ -107,11 +107,11 @@ public class SessionAwareMethodInterceptorUnitTests {
public void usesCacheForMethodLookup() {
MethodCache cache = (MethodCache) ReflectionTestUtils.getField(SessionAwareMethodInterceptor.class, "METHOD_CACHE");
Method countMethod = ClassUtils.getMethod(MongoCollection.class, "count");
Method countMethod = ClassUtils.getMethod(MongoCollection.class, "countDocuments");
assertThat(cache.contains(countMethod, MongoCollection.class)).isFalse();
collection.count();
collection.countDocuments();
assertThat(cache.contains(countMethod, MongoCollection.class)).isTrue();
}

View File

@@ -154,7 +154,7 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
when(db.runCommand(any(), any(Class.class))).thenReturn(commandResultDocument);
when(collection.find(any(org.bson.Document.class), any(Class.class))).thenReturn(findIterable);
when(collection.mapReduce(any(), any(), eq(Document.class))).thenReturn(mapReduceIterable);
when(collection.count(any(Bson.class), any(CountOptions.class))).thenReturn(1L); // TODO: MongoDB 4 - fix me
when(collection.countDocuments(any(Bson.class), any(CountOptions.class))).thenReturn(1L); // TODO: MongoDB 4 - fix me
when(collection.getNamespace()).thenReturn(new MongoNamespace("db.mock-collection"));
when(collection.aggregate(any(List.class), any())).thenReturn(aggregateIterable);
when(collection.withReadPreference(any())).thenReturn(collection);
@@ -735,7 +735,7 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
template.exists(new BasicQuery("{}").collation(Collation.of("fr")), AutogenerateableId.class);
ArgumentCaptor<CountOptions> options = ArgumentCaptor.forClass(CountOptions.class);
verify(collection).count(any(), options.capture());
verify(collection).countDocuments(any(), options.capture());
assertThat(options.getValue().getCollation())
.isEqualTo(com.mongodb.client.model.Collation.builder().locale("fr").build());
@@ -926,7 +926,7 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
template.count(new BasicQuery("{}").collation(Collation.of("fr")), AutogenerateableId.class);
ArgumentCaptor<CountOptions> options = ArgumentCaptor.forClass(CountOptions.class);
verify(collection).count(any(), options.capture());
verify(collection).countDocuments(any(), options.capture());
assertThat(options.getValue().getCollation())
.isEqualTo(com.mongodb.client.model.Collation.builder().locale("fr").build());
@@ -939,7 +939,7 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
template.count(new BasicQuery("{}").withHint(queryHint), AutogenerateableId.class);
ArgumentCaptor<CountOptions> options = ArgumentCaptor.forClass(CountOptions.class);
verify(collection).count(any(), options.capture());
verify(collection).countDocuments(any(), options.capture());
assertThat(options.getValue().getHint()).isEqualTo(queryHint);
}
@@ -1068,7 +1068,7 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
template.count(new BasicQuery("{}").skip(100), AutogenerateableId.class);
ArgumentCaptor<CountOptions> options = ArgumentCaptor.forClass(CountOptions.class);
verify(collection).count(any(), options.capture());
verify(collection).countDocuments(any(), options.capture());
assertThat(options.getValue().getSkip()).isEqualTo(100);
}
@@ -1079,7 +1079,7 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
template.count(new BasicQuery("{}").limit(10), AutogenerateableId.class);
ArgumentCaptor<CountOptions> options = ArgumentCaptor.forClass(CountOptions.class);
verify(collection).count(any(), options.capture());
verify(collection).countDocuments(any(), options.capture());
assertThat(options.getValue().getLimit()).isEqualTo(10);
}
@@ -1150,7 +1150,7 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
template.exists(new BasicQuery("{}"), Sith.class);
ArgumentCaptor<CountOptions> options = ArgumentCaptor.forClass(CountOptions.class);
verify(collection).count(any(), options.capture());
verify(collection).countDocuments(any(), options.capture());
assertThat(options.getValue().getCollation())
.isEqualTo(com.mongodb.client.model.Collation.builder().locale("de_AT").build());

View File

@@ -126,7 +126,7 @@ public class ReactiveMongoTemplateUnitTests {
when(collection.find(any(Document.class), any(Class.class))).thenReturn(findPublisher);
when(collection.aggregate(anyList())).thenReturn(aggregatePublisher);
when(collection.aggregate(anyList(), any(Class.class))).thenReturn(aggregatePublisher);
when(collection.count(any(), any(CountOptions.class))).thenReturn(Mono.just(0L));
when(collection.countDocuments(any(), any(CountOptions.class))).thenReturn(Mono.just(0L));
when(collection.updateOne(any(), any(Bson.class), any(UpdateOptions.class))).thenReturn(updateResultPublisher);
when(collection.updateMany(any(Bson.class), any(Bson.class), any())).thenReturn(updateResultPublisher);
when(collection.findOneAndUpdate(any(), any(Bson.class), any(FindOneAndUpdateOptions.class)))
@@ -391,7 +391,7 @@ public class ReactiveMongoTemplateUnitTests {
template.count(new Query().skip(10), Person.class, "star-wars").subscribe();
ArgumentCaptor<CountOptions> options = ArgumentCaptor.forClass(CountOptions.class);
verify(collection).count(any(), options.capture());
verify(collection).countDocuments(any(), options.capture());
assertThat(options.getValue().getSkip()).isEqualTo(10);
}
@@ -402,7 +402,7 @@ public class ReactiveMongoTemplateUnitTests {
template.count(new Query().limit(100), Person.class, "star-wars").subscribe();
ArgumentCaptor<CountOptions> options = ArgumentCaptor.forClass(CountOptions.class);
verify(collection).count(any(), options.capture());
verify(collection).countDocuments(any(), options.capture());
assertThat(options.getValue().getLimit()).isEqualTo(100);
}
@@ -414,7 +414,7 @@ public class ReactiveMongoTemplateUnitTests {
template.count(new Query().withHint(queryHint), Person.class, "star-wars").subscribe();
ArgumentCaptor<CountOptions> options = ArgumentCaptor.forClass(CountOptions.class);
verify(collection).count(any(), options.capture());
verify(collection).countDocuments(any(), options.capture());
assertThat(options.getValue().getHint()).isEqualTo(queryHint);
}

View File

@@ -111,7 +111,7 @@ public class ReactiveSessionBoundMongoTemplateUnitTests {
when(collection.deleteMany(any(ClientSession.class), any(), any())).thenReturn(resultPublisher);
when(collection.insertOne(any(ClientSession.class), any(Document.class))).thenReturn(resultPublisher);
when(collection.aggregate(any(ClientSession.class), anyList(), any(Class.class))).thenReturn(aggregatePublisher);
when(collection.count(any(ClientSession.class), any(), any(CountOptions.class))).thenReturn(resultPublisher);
when(collection.countDocuments(any(ClientSession.class), any(), any(CountOptions.class))).thenReturn(resultPublisher);
when(collection.drop(any(ClientSession.class))).thenReturn(resultPublisher);
when(collection.findOneAndUpdate(any(ClientSession.class), any(), any(Bson.class), any()))
.thenReturn(resultPublisher);
@@ -224,7 +224,7 @@ public class ReactiveSessionBoundMongoTemplateUnitTests {
template.count(new Query(), Person.class).subscribe();
verify(collection).count(eq(clientSession), any(), any(CountOptions.class));
verify(collection).countDocuments(eq(clientSession), any(), any(CountOptions.class));
}
@Test // DATAMONGO-1880

View File

@@ -284,7 +284,6 @@ public class SessionBoundMongoTemplateTests {
}
@Test // DATAMONGO-2012
@Ignore("error 2 (BadValue): $match does not support $geoNear, $near, and $nearSphere")
public void countWithGeoInTransaction() {
if (!template.collectionExists(Person.class)) {

View File

@@ -226,7 +226,7 @@ public class SessionBoundMongoTemplateUnitTests {
template.count(new Query(), Person.class);
verify(collection).count(eq(clientSession), any(), any(CountOptions.class));
verify(collection).countDocuments(eq(clientSession), any(), any(CountOptions.class));
}
@Test // DATAMONGO-1880

View File

@@ -890,6 +890,96 @@ public class QueryMapperUnitTests {
assertThat(target).isEqualTo(new org.bson.Document("_id", "id-1"));
}
@Test // DATAMONGO-2059
public void nearToGeoWithinWithoutDistance() {
Query source = query(where("location").near(new Point(-73.99171, 40.738868)));
org.bson.Document target = postProcessQueryForCount(source);
assertThat(target).isEqualTo(org.bson.Document
.parse("{\"location\": {\"$geoWithin\": {\"$center\": [[-73.99171, 40.738868], 1.7976931348623157E308]}}}"));
}
@Test // DATAMONGO-2059
public void nearSphereToGeoWithinWithoutDistance() {
Query source = query(where("location").nearSphere(new Point(-73.99171, 40.738868)));
org.bson.Document target = postProcessQueryForCount(source);
assertThat(target).isEqualTo(org.bson.Document.parse(
"{\"location\": {\"$geoWithin\": {\"$centerSphere\": [[-73.99171, 40.738868], 1.7976931348623157E308]}}}"));
}
@Test // DATAMONGO-2059
public void nearToGeoWithinWithMaxDistance() {
Query source = query(where("location").near(new Point(-73.99171, 40.738868)).maxDistance(10));
org.bson.Document target = postProcessQueryForCount(source);
assertThat(target).isEqualTo(
org.bson.Document.parse("{\"location\": {\"$geoWithin\": {\"$center\": [[-73.99171, 40.738868], 10.0]}}}"));
}
@Test // DATAMONGO-2059
public void nearSphereToGeoWithinWithMaxDistance() {
Query source = query(where("location").nearSphere(new Point(-73.99171, 40.738868)).maxDistance(10));
org.bson.Document target = postProcessQueryForCount(source);
assertThat(target).isEqualTo(org.bson.Document
.parse("{\"location\": {\"$geoWithin\": {\"$centerSphere\": [[-73.99171, 40.738868], 10.0]}}}"));
}
@Test // DATAMONGO-2059
public void nearToGeoWithinWithMinDistance() {
Query source = query(where("location").near(new Point(-73.99171, 40.738868)).minDistance(0.01));
org.bson.Document target = postProcessQueryForCount(source);
assertThat(target).isEqualTo(org.bson.Document.parse(
"{\"$and\":[{\"$nor\":[{\"location\":{\"$geoWithin\":{\"$center\":[ [ -73.99171, 40.738868 ], 0.01]}}}]},"
+ " {\"location\":{\"$geoWithin\":{\"$center\":[ [ -73.99171, 40.738868 ], 1.7976931348623157E308]}}}]}"));
}
@Test // DATAMONGO-2059
public void nearToGeoWithinWithMaxDistanceAndCombinedWithOtherCriteria() {
Query source = query(
where("name").is("food").and("location").near(new Point(-73.99171, 40.738868)).maxDistance(10));
org.bson.Document target = postProcessQueryForCount(source);
assertThat(target).isEqualTo(org.bson.Document
.parse("{\"name\": \"food\", \"location\": {\"$geoWithin\": {\"$center\": [[-73.99171, 40.738868], 10.0]}}}"));
}
@Test // DATAMONGO-2059
public void nearToGeoWithinWithMinDistanceOrCombinedWithOtherCriteria() {
Query source = query(new Criteria().orOperator(where("name").is("food"),
where("location").near(new Point(-73.99171, 40.738868)).minDistance(0.01)));
org.bson.Document target = postProcessQueryForCount(source);
assertThat(target).isEqualTo(org.bson.Document.parse(
"{\"$or\" : [ { \"name\": \"food\" }, {\"$and\":[{\"$nor\":[{\"location\":{\"$geoWithin\":{\"$center\":[ [ -73.99171, 40.738868 ], 0.01]}}}]},{\"location\":{\"$geoWithin\":{\"$center\":[ [ -73.99171, 40.738868 ], 1.7976931348623157E308]}}}]} ]}"));
}
@Test // DATAMONGO-2059
public void nearToGeoWithinWithMaxDistanceOrCombinedWithOtherCriteria() {
Query source = query(new Criteria().orOperator(where("name").is("food"),
where("location").near(new Point(-73.99171, 40.738868)).maxDistance(10)));
org.bson.Document target = postProcessQueryForCount(source);
assertThat(target).isEqualTo(org.bson.Document.parse(
"{\"$or\" : [ { \"name\": \"food\" }, {\"location\": {\"$geoWithin\": {\"$center\": [[-73.99171, 40.738868], 10.0]}}} ]}"));
}
private org.bson.Document postProcessQueryForCount(Query source) {
org.bson.Document intermediate = mapper.getMappedObject(source.getQueryObject(), (MongoPersistentEntity<?>) null);
return QueryMapper.processCountFilter(intermediate);
}
@Document
public class Foo {
@Id private ObjectId id;

View File

@@ -120,24 +120,33 @@ public abstract class AbstractGeoSpatialTests {
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);
Query query = query(where("location").within(circle));
List<Venue> venues = template.find(query, Venue.class);
assertThat(venues).hasSize(7);
assertThat(template.count(query, Venue.class)).isEqualTo(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);
Query query = query(where("location").withinSphere(circle));
List<Venue> venues = template.find(query, Venue.class);
assertThat(venues).hasSize(11);
assertThat(template.count(query, Venue.class)).isEqualTo(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);
Query query = query(where("location").within(box));
List<Venue> venues = template.find(query, Venue.class);
assertThat(venues).hasSize(4);
assertThat(template.count(query, Venue.class)).isEqualTo(4);
}
@Test
@@ -150,8 +159,10 @@ public abstract class AbstractGeoSpatialTests {
Polygon polygon = new Polygon(first, second, third, fourth);
List<Venue> venues = template.find(query(where("location").within(polygon)), Venue.class);
Query query = query(where("location").within(polygon));
List<Venue> venues = template.find(query, Venue.class);
assertThat(venues).hasSize(4);
assertThat(template.count(query, Venue.class)).isEqualTo(4);
}
@Test
@@ -159,8 +170,10 @@ public abstract class AbstractGeoSpatialTests {
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).hasSize(11);
assertThat(template.count(query, Venue.class)).isEqualTo(11);
}
@Test // DATAMONGO-1360

View File

@@ -22,6 +22,7 @@ import static org.springframework.data.mongodb.core.query.Query.*;
import java.util.List;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.data.domain.Sort.Direction;
@@ -36,6 +37,7 @@ import org.springframework.data.mongodb.core.index.IndexField;
import org.springframework.data.mongodb.core.index.IndexInfo;
import org.springframework.data.mongodb.core.index.IndexOperations;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
/**
* @author Christoph Strobl
@@ -72,11 +74,23 @@ public class GeoSpatial2DSphereTests extends AbstractGeoSpatialTests {
@Test // DATAMONGO-1110
public void nearSphereWithMinDistance() {
Point point = new Point(-73.99171, 40.738868);
List<Venue> venues = template.find(query(where("location").nearSphere(point).minDistance(0.01)), Venue.class);
Query query = query(where("location").nearSphere(point).minDistance(0.01));
List<Venue> venues = template.find(query, Venue.class);
assertThat(venues.size()).isEqualTo(1);
}
@Test
public void countNearSphereWithMinDistance() {
Point point = new Point(-73.99171, 40.738868);
Query query = query(where("location").nearSphere(point).minDistance(0.01));
assertThat(template.count(query, Venue.class)).isEqualTo(1);
}
@Override
protected void createIndex() {
template.indexOps(Venue.class).ensureIndex(new GeospatialIndex("location").typed(GeoSpatialIndexType.GEO_2DSPHERE));

View File

@@ -32,6 +32,7 @@ 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.index.IndexOperations;
import org.springframework.data.mongodb.core.query.Query;
/**
* Modified from https://github.com/deftlabs/mongo-java-geospatial-example
@@ -45,9 +46,13 @@ 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);
Query query = query(where("location").near(point).maxDistance(0.01));
List<Venue> venues = template.find(query, Venue.class);
assertThat(venues.size()).isEqualTo(7);
assertThat(template.count(query, Venue.class)).isEqualTo(7);
}
@Test // DATAMONGO-360