DATAMONGO-1418 - Add support for $out operator in aggregations.
We now support the $out operator via Aggregation.out(…) to store aggregation results in a collection. Using the $out operator returns an empty list in AggregationResults. Original pull request: #361. CLA: 172720160413124705 (Nikolai Bogdanov)
This commit is contained in:
committed by
Mark Paluch
parent
ba8ece334a
commit
0db36aff8f
@@ -45,6 +45,7 @@ import com.mongodb.DBObject;
|
||||
* @author Mark Paluch
|
||||
* @author Alessio Fachechi
|
||||
* @author Christoph Strobl
|
||||
* @author Nikolay Bogdanov
|
||||
* @since 1.3
|
||||
*/
|
||||
public class Aggregation {
|
||||
@@ -160,6 +161,13 @@ public class Aggregation {
|
||||
Assert.isTrue(!aggregationOperations.isEmpty(), "At least one AggregationOperation has to be provided");
|
||||
Assert.notNull(options, "AggregationOptions must not be null!");
|
||||
|
||||
//check $out is the last operation if exist
|
||||
for (int i = 0; i < aggregationOperations.size(); i++) {
|
||||
if (aggregationOperations.get(i) instanceof OutOperation && i != aggregationOperations.size() - 1) {
|
||||
throw new IllegalArgumentException("The $out operator must be the last stage in the pipeline.");
|
||||
}
|
||||
}
|
||||
|
||||
this.operations = aggregationOperations;
|
||||
this.options = options;
|
||||
}
|
||||
@@ -318,6 +326,20 @@ public class Aggregation {
|
||||
return new MatchOperation(criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link OutOperation} using the given collection name. This operation must be the last operation
|
||||
* in the pipeline.
|
||||
*
|
||||
* @param outCollectionName collection name to export aggregation results. The {@link OutOperation} creates a new
|
||||
* collection in the current database if one does not already exist. The collection is
|
||||
* not visible until the aggregation completes. If the aggregation fails, MongoDB does
|
||||
* not create the collection. Must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static OutOperation out(String outCollectionName) {
|
||||
return new OutOperation(outCollectionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link LookupOperation}.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2016 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Encapsulates the {@code $out}-operation.
|
||||
* <p>
|
||||
* We recommend to use the static factory method {@link Aggregation#out(String)} instead of creating instances of this
|
||||
* class directly.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/aggregation/out/
|
||||
* @author Nikolay Bogdanov
|
||||
*/
|
||||
public class OutOperation implements AggregationOperation {
|
||||
|
||||
private final String collectionName;
|
||||
|
||||
/**
|
||||
* @param outCollectionName Collection name to export the results. Must not be {@literal null}.
|
||||
*/
|
||||
public OutOperation(String outCollectionName) {
|
||||
Assert.notNull(outCollectionName, "Collection name must not be null!");
|
||||
this.collectionName = outCollectionName;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public DBObject toDBObject(AggregationOperationContext context) {
|
||||
return new BasicDBObject("$out", collectionName);
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,7 @@ import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.Venue;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationTests.CarDescriptor.Entry;
|
||||
import org.springframework.data.mongodb.core.index.GeospatialIndex;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.NearQuery;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.repository.Person;
|
||||
@@ -78,6 +79,7 @@ import com.mongodb.util.JSON;
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @author Nikolay Bogdanov
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration("classpath:infrastructure.xml")
|
||||
@@ -1182,6 +1184,50 @@ public class AggregationTests {
|
||||
assertThat(firstItem, isBsonObject().containing("linkedPerson.[0].firstname", "u1"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1418
|
||||
*/
|
||||
@Test
|
||||
public void shouldCreateOutputCollection() {
|
||||
|
||||
assumeTrue(mongoVersion.isGreaterThanOrEqualTo(TWO_DOT_SIX));
|
||||
|
||||
mongoTemplate.save(new Person("Anna", "Ivanova", 21, Person.Sex.FEMALE));
|
||||
mongoTemplate.save(new Person("Pavel", "Sidorov", 36, Person.Sex.MALE));
|
||||
mongoTemplate.save(new Person("Anastasia", "Volochkova", 29, Person.Sex.FEMALE));
|
||||
mongoTemplate.save(new Person("Igor", "Stepanov", 31, Person.Sex.MALE));
|
||||
mongoTemplate.save(new Person("Leoniv", "Yakubov", 55, Person.Sex.MALE));
|
||||
|
||||
String tempOutCollection = "personQueryTemp";
|
||||
TypedAggregation<Person> agg = newAggregation(Person.class, //
|
||||
group("sex").count().as("count"), //
|
||||
sort(DESC, "count"), //
|
||||
out(tempOutCollection));
|
||||
|
||||
AggregationResults<DBObject> results = mongoTemplate.aggregate(agg, DBObject.class);
|
||||
assertThat(results.getMappedResults(), is(empty()));
|
||||
|
||||
List<DBObject> list = mongoTemplate.findAll(DBObject.class, tempOutCollection);
|
||||
|
||||
assertThat(list, hasSize(2));
|
||||
assertThat(list.get(0), isBsonObject().containing("_id", "MALE").containing("count", 3));
|
||||
assertThat(list.get(1), isBsonObject().containing("_id", "FEMALE").containing("count", 2));
|
||||
|
||||
mongoTemplate.dropCollection(tempOutCollection);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1418
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void outShouldOutBeTheLastOperation() {
|
||||
|
||||
newAggregation(match(new Criteria()), //
|
||||
group("field1").count().as("totalCount"), //
|
||||
out("collection1"), //
|
||||
skip(100));
|
||||
}
|
||||
|
||||
private void createUsersWithReferencedPersons() {
|
||||
|
||||
mongoTemplate.dropCollection(User.class);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2016 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link OutOperation}.
|
||||
*
|
||||
* @author Nikolay Bogdanov
|
||||
*/
|
||||
public class OutOperationUnitTest {
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldCheckNPEInCreation() {
|
||||
new OutOperation(null);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user