Browse Source

DATAMONGO-1334 - Map-reduce operations now honor MapReduceOptions.limit.

We now also consider the limit set via MapReduceOptions when executing mapReduce operations via MongoTemplate.mapReduce(…).

MapReduceOptions.limit(…) supersedes a potential limit set via the Query itself. This change also allows to define a limit even when no explicit Query is used.

Original pull request: #338.
pull/663/head
Christoph Strobl 10 years ago committed by Oliver Gierke
parent
commit
b0336c27a9
  1. 7
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
  2. 17
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapreduce/MapReduceOptions.java
  3. 111
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java
  4. 30
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapreduce/MapReduceOptionsTests.java

7
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java

@ -1579,8 +1579,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware { @@ -1579,8 +1579,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
throw new InvalidDataAccessApiUsageException(
"Can not use skip or field specification with map reduce operations");
}
if (query.getLimit() > 0) {
if (query.getLimit() > 0 && mapReduceOptions.getLimit() == null) {
mapReduceCommand.setLimit(query.getLimit());
}
if (query.getSortObject() != null) {
@ -1588,6 +1587,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware { @@ -1588,6 +1587,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
}
}
if (mapReduceOptions.getLimit() != null && mapReduceOptions.getLimit().intValue() > 0) {
mapReduceCommand.setLimit(mapReduceOptions.getLimit());
}
if (mapReduceOptions.getJavaScriptMode() != null) {
mapReduceCommand.setJsMode(true);
}

17
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapreduce/MapReduceOptions.java

@ -45,6 +45,8 @@ public class MapReduceOptions { @@ -45,6 +45,8 @@ public class MapReduceOptions {
private Boolean verbose = true;
private Integer limit;
private Map<String, Object> extraOptions = new HashMap<String, Object>();
/**
@ -64,6 +66,8 @@ public class MapReduceOptions { @@ -64,6 +66,8 @@ public class MapReduceOptions {
* @return MapReduceOptions so that methods can be chained in a fluent API style
*/
public MapReduceOptions limit(int limit) {
this.limit = limit;
return this;
}
@ -247,6 +251,15 @@ public class MapReduceOptions { @@ -247,6 +251,15 @@ public class MapReduceOptions {
return this.scopeVariables;
}
/**
* Get the maximum number of documents for the input into the map function.
*
* @return {@literal null} if not set.
*/
public Integer getLimit() {
return limit;
}
public DBObject getOptionsObject() {
BasicDBObject cmd = new BasicDBObject();
@ -264,6 +277,10 @@ public class MapReduceOptions { @@ -264,6 +277,10 @@ public class MapReduceOptions {
cmd.put("scope", scopeVariables);
}
if (limit != null) {
cmd.put("limit", limit);
}
if (!extraOptions.keySet().isEmpty()) {
cmd.putAll(extraOptions);
}

111
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java

@ -1,5 +1,5 @@ @@ -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.
@ -52,6 +52,7 @@ import org.springframework.data.mongodb.core.convert.MappingMongoConverter; @@ -52,6 +52,7 @@ import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.NearQuery;
@ -66,6 +67,8 @@ import com.mongodb.DB; @@ -66,6 +67,8 @@ import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.MapReduceCommand;
import com.mongodb.MapReduceOutput;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
import com.mongodb.ReadPreference;
@ -422,6 +425,112 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests { @@ -422,6 +425,112 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
verify(this.db, times(1)).command(Mockito.any(DBObject.class));
}
/**
* @see DATAMONGO-1334
*/
@Test
public void mapReduceShouldUseZeroAsDefaultLimit() {
ArgumentCaptor<MapReduceCommand> captor = ArgumentCaptor.forClass(MapReduceCommand.class);
MapReduceOutput output = mock(MapReduceOutput.class);
when(output.results()).thenReturn(Collections.<DBObject> emptySet());
when(collection.mapReduce(Mockito.any(MapReduceCommand.class))).thenReturn(output);
Query query = new BasicQuery("{'foo':'bar'}");
template.mapReduce(query, "collection", "function(){}", "function(key,values){}", Wrapper.class);
verify(collection).mapReduce(captor.capture());
assertThat(captor.getValue().getLimit(), is(0));
}
/**
* @see DATAMONGO-1334
*/
@Test
public void mapReduceShouldPickUpLimitFromQuery() {
ArgumentCaptor<MapReduceCommand> captor = ArgumentCaptor.forClass(MapReduceCommand.class);
MapReduceOutput output = mock(MapReduceOutput.class);
when(output.results()).thenReturn(Collections.<DBObject> emptySet());
when(collection.mapReduce(Mockito.any(MapReduceCommand.class))).thenReturn(output);
Query query = new BasicQuery("{'foo':'bar'}");
query.limit(100);
template.mapReduce(query, "collection", "function(){}", "function(key,values){}", Wrapper.class);
verify(collection).mapReduce(captor.capture());
assertThat(captor.getValue().getLimit(), is(100));
}
/**
* @see DATAMONGO-1334
*/
@Test
public void mapReduceShouldPickUpLimitFromOptions() {
ArgumentCaptor<MapReduceCommand> captor = ArgumentCaptor.forClass(MapReduceCommand.class);
MapReduceOutput output = mock(MapReduceOutput.class);
when(output.results()).thenReturn(Collections.<DBObject> emptySet());
when(collection.mapReduce(Mockito.any(MapReduceCommand.class))).thenReturn(output);
Query query = new BasicQuery("{'foo':'bar'}");
template.mapReduce(query, "collection", "function(){}", "function(key,values){}",
new MapReduceOptions().limit(1000), Wrapper.class);
verify(collection).mapReduce(captor.capture());
assertThat(captor.getValue().getLimit(), is(1000));
}
/**
* @see DATAMONGO-1334
*/
@Test
public void mapReduceShouldPickUpLimitFromOptionsWhenQueryIsNotPresent() {
ArgumentCaptor<MapReduceCommand> captor = ArgumentCaptor.forClass(MapReduceCommand.class);
MapReduceOutput output = mock(MapReduceOutput.class);
when(output.results()).thenReturn(Collections.<DBObject> emptySet());
when(collection.mapReduce(Mockito.any(MapReduceCommand.class))).thenReturn(output);
template.mapReduce("collection", "function(){}", "function(key,values){}", new MapReduceOptions().limit(1000),
Wrapper.class);
verify(collection).mapReduce(captor.capture());
assertThat(captor.getValue().getLimit(), is(1000));
}
/**
* @see DATAMONGO-1334
*/
@Test
public void mapReduceShouldPickUpLimitFromOptionsEvenWhenQueryDefinesItDifferently() {
ArgumentCaptor<MapReduceCommand> captor = ArgumentCaptor.forClass(MapReduceCommand.class);
MapReduceOutput output = mock(MapReduceOutput.class);
when(output.results()).thenReturn(Collections.<DBObject> emptySet());
when(collection.mapReduce(Mockito.any(MapReduceCommand.class))).thenReturn(output);
Query query = new BasicQuery("{'foo':'bar'}");
query.limit(100);
template.mapReduce(query, "collection", "function(){}", "function(key,values){}",
new MapReduceOptions().limit(1000), Wrapper.class);
verify(collection).mapReduce(captor.capture());
assertThat(captor.getValue().getLimit(), is(1000));
}
class AutogenerateableId {
@Id BigInteger id;

30
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapreduce/MapReduceOptionsTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2010-2011 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.
@ -15,12 +15,40 @@ @@ -15,12 +15,40 @@
*/
package org.springframework.data.mongodb.core.mapreduce;
import static org.junit.Assert.*;
import static org.springframework.data.mongodb.test.util.IsBsonObject.*;
import org.junit.Test;
/**
* @author Mark Pollack
* @author Oliver Gierke
* @author Christoph Strobl
*/
public class MapReduceOptionsTests {
@Test
public void testFinalize() {
new MapReduceOptions().finalizeFunction("code");
}
/**
* @see DATAMONGO-1334
*/
@Test
public void limitShouldBeIncludedCorrectly() {
MapReduceOptions options = new MapReduceOptions();
options.limit(10);
assertThat(options.getOptionsObject(), isBsonObject().containing("limit", 10));
}
/**
* @see DATAMONGO-1334
*/
@Test
public void limitShouldNotBePresentInDboWhenNotSet() {
assertThat(new MapReduceOptions().getOptionsObject(), isBsonObject().notContaining("limit"));
}
}

Loading…
Cancel
Save