Skip to content

DATAMONGO-1334 - Honor MapReduceOptions.limit for mapReduce operations. #338

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.9.0.BUILD-SNAPSHOT</version>
<version>1.9.0.DATAMONGO-1334-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Spring Data MongoDB</name>
Expand Down
4 changes: 2 additions & 2 deletions spring-data-mongodb-cross-store/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.9.0.BUILD-SNAPSHOT</version>
<version>1.9.0.DATAMONGO-1334-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down Expand Up @@ -48,7 +48,7 @@
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.9.0.BUILD-SNAPSHOT</version>
<version>1.9.0.DATAMONGO-1334-SNAPSHOT</version>
</dependency>

<dependency>
Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.9.0.BUILD-SNAPSHOT</version>
<version>1.9.0.DATAMONGO-1334-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb-log4j/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.9.0.BUILD-SNAPSHOT</version>
<version>1.9.0.DATAMONGO-1334-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.9.0.BUILD-SNAPSHOT</version>
<version>1.9.0.DATAMONGO-1334-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1599,15 +1599,18 @@ private void copyMapReduceOptionsToCommand(Query query, MapReduceOptions mapRedu
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) {
mapReduceCommand.setSort(queryMapper.getMappedObject(query.getSortObject(), null));
}
}

if (mapReduceOptions.getLimit() != null && mapReduceOptions.getLimit().intValue() > 0) {
mapReduceCommand.setLimit(mapReduceOptions.getLimit());
}

if (mapReduceOptions.getJavaScriptMode() != null) {
mapReduceCommand.setJsMode(true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ public class MapReduceOptions {

private Boolean verbose = true;

private Integer limit;

private Map<String, Object> extraOptions = new HashMap<String, Object>();

/**
Expand All @@ -64,6 +66,8 @@ public static MapReduceOptions options() {
* @return MapReduceOptions so that methods can be chained in a fluent API style
*/
public MapReduceOptions limit(int limit) {

this.limit = limit;
return this;
}

Expand Down Expand Up @@ -247,6 +251,16 @@ public Map<String, Object> getScopeVariables() {
return this.scopeVariables;
}

/**
* Get the maximum number of documents for the input into the map function.
*
* @return {@literal null} if not set.
* @since 1.7
*/
public Integer getLimit() {
return limit;
}

public DBObject getOptionsObject() {
BasicDBObject cmd = new BasicDBObject();

Expand All @@ -264,6 +278,10 @@ public DBObject getOptionsObject() {
cmd.put("scope", scopeVariables);
}

if (limit != null) {
cmd.put("limit", limit);
}

if (!extraOptions.keySet().isEmpty()) {
cmd.putAll(extraOptions);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -52,6 +52,7 @@
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;
Expand All @@ -66,6 +67,8 @@
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;
Expand Down Expand Up @@ -422,6 +425,112 @@ public void geoNearShouldIgnoreReadPreferenceWhenNotSet() {
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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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"));
}
}