diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/Aggregation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/Aggregation.java index e5a587c9b..caf5f2ae1 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/Aggregation.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/Aggregation.java @@ -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}. * diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/OutOperation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/OutOperation.java new file mode 100644 index 000000000..68b357a62 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/OutOperation.java @@ -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. + *
+ * 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);
+ }
+}
diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java
index 4caf61f07..1de24d41b 100644
--- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java
+++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java
@@ -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