DATAMONGO-1734 - Polish MongoTemplate.exists execution.

Optimize execution by using count() limited to 1 element.

Original pull request: #479.
This commit is contained in:
Christoph Strobl
2017-07-06 14:03:44 +02:00
committed by Mark Paluch
parent 7fb5c7d97c
commit d3b9f91478
2 changed files with 30 additions and 8 deletions

View File

@@ -20,6 +20,7 @@ import static org.springframework.data.mongodb.core.query.SerializationUtils.*;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@@ -131,6 +132,7 @@ import com.mongodb.client.MapReduceIterable;
import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor; import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase; import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.CountOptions;
import com.mongodb.client.model.CreateCollectionOptions; import com.mongodb.client.model.CreateCollectionOptions;
import com.mongodb.client.model.DeleteOptions; import com.mongodb.client.model.DeleteOptions;
import com.mongodb.client.model.Filters; import com.mongodb.client.model.Filters;
@@ -609,14 +611,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
} }
Document mappedQuery = queryMapper.getMappedObject(query.getQueryObject(), getPersistentEntity(entityClass)); Document mappedQuery = queryMapper.getMappedObject(query.getQueryObject(), getPersistentEntity(entityClass));
FindIterable<Document> iterable = execute(collectionName, new FindCallback(mappedQuery));
if (query.getCollation().isPresent()) { return execute(collectionName, new ExistsCallback(mappedQuery,
iterable = iterable query.getCollation().map(org.springframework.data.mongodb.core.Collation::toMongoCollation).orElse(null)));
.collation(query.getCollation().map(org.springframework.data.mongodb.core.Collation::toMongoCollation).get());
}
return iterable.iterator().hasNext();
} }
// Find methods that take a Query to express the query and that return a List of objects. // Find methods that take a Query to express the query and that return a List of objects.
@@ -2429,6 +2426,25 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
} }
} }
/**
* Optimized {@link CollectionCallback} that takes an already mappend query and a nullable
* {@link com.mongodb.client.model.Collation} to execute a count query limited to one element.
*
* @author Christoph Strobl
* @since 2.0
*/
@RequiredArgsConstructor
private static class ExistsCallback implements CollectionCallback<Boolean> {
private final Document mappedQuery;
private final com.mongodb.client.model.Collation collation;
@Override
public Boolean doInCollection(MongoCollection<Document> collection) throws MongoException, DataAccessException {
return collection.count(mappedQuery, new CountOptions().limit(1).collation(collation)) > 0;
}
}
/** /**
* Simple {@link CollectionCallback} that takes a query {@link Document} plus an optional fields specification * Simple {@link CollectionCallback} that takes a query {@link Document} plus an optional fields specification
* {@link Document} and executes that against the {@link DBCollection}. * {@link Document} and executes that against the {@link DBCollection}.

View File

@@ -81,6 +81,7 @@ import com.mongodb.client.MapReduceIterable;
import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor; import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase; import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.CountOptions;
import com.mongodb.client.model.DeleteOptions; import com.mongodb.client.model.DeleteOptions;
import com.mongodb.client.model.FindOneAndDeleteOptions; import com.mongodb.client.model.FindOneAndDeleteOptions;
import com.mongodb.client.model.FindOneAndUpdateOptions; import com.mongodb.client.model.FindOneAndUpdateOptions;
@@ -123,6 +124,7 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
when(db.runCommand(Mockito.any(), Mockito.any(Class.class))).thenReturn(commandResultDocument); when(db.runCommand(Mockito.any(), Mockito.any(Class.class))).thenReturn(commandResultDocument);
when(collection.find(Mockito.any(org.bson.Document.class))).thenReturn(findIterable); when(collection.find(Mockito.any(org.bson.Document.class))).thenReturn(findIterable);
when(collection.mapReduce(Mockito.any(), Mockito.any())).thenReturn(mapReduceIterable); when(collection.mapReduce(Mockito.any(), Mockito.any())).thenReturn(mapReduceIterable);
when(collection.count(any(), any())).thenReturn(1L);
when(findIterable.projection(Mockito.any())).thenReturn(findIterable); when(findIterable.projection(Mockito.any())).thenReturn(findIterable);
when(findIterable.sort(Mockito.any(org.bson.Document.class))).thenReturn(findIterable); when(findIterable.sort(Mockito.any(org.bson.Document.class))).thenReturn(findIterable);
when(findIterable.modifiers(Mockito.any(org.bson.Document.class))).thenReturn(findIterable); when(findIterable.modifiers(Mockito.any(org.bson.Document.class))).thenReturn(findIterable);
@@ -666,7 +668,11 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
template.exists(new BasicQuery("{}").collation(Collation.of("fr")), AutogenerateableId.class); template.exists(new BasicQuery("{}").collation(Collation.of("fr")), AutogenerateableId.class);
verify(findIterable).collation(eq(com.mongodb.client.model.Collation.builder().locale("fr").build())); ArgumentCaptor<CountOptions> options = ArgumentCaptor.forClass(CountOptions.class);
verify(collection).count(any(), options.capture());
assertThat(options.getValue().getCollation(),
is(equalTo(com.mongodb.client.model.Collation.builder().locale("fr").build())));
} }
@Test // DATAMONGO-1518 @Test // DATAMONGO-1518