Skip to content

DATAMONGO-1418 New $out operator for the aggregation framework. #361

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
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
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*
/*
* Copyright 2013-2016 the original author or authors.
*
Expand Down Expand Up @@ -44,6 +45,7 @@
* @author Oliver Gierke
* @author Mark Paluch
* @author Alessio Fachechi
* @author Nikolay Bogdanov
* @since 1.3
*/
public class Aggregation {
Expand Down Expand Up @@ -159,6 +161,13 @@ protected Aggregation(List<AggregationOperation> aggregationOperations, Aggregat
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;
}
Expand Down Expand Up @@ -273,6 +282,20 @@ public static MatchOperation match(Criteria criteria) {
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}.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
* @author Oliver Gierke
* @author Christoph Strobl
* @author Mark Paluch
* @author Nikolay Bogdanov
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:infrastructure.xml")
Expand Down Expand Up @@ -1120,6 +1121,40 @@ public void shouldGroupByAndLookupPeopleCorectly() {
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);
assertTrue(results.getMappedResults().isEmpty());

List<DBObject> list = mongoTemplate.findAll(DBObject.class, tempOutCollection);
assertEquals("Size incorrect in temp collection", 2, list.size());
DBObject first = list.get(0);
DBObject second = list.get(1);
assertThat(first, isBsonObject().containing("_id", "MALE")
.containing("count", 3));
assertThat(second, isBsonObject().containing("_id", "FEMALE")
.containing("count", 2));
mongoTemplate.dropCollection(tempOutCollection);
}

private void createUsersWithReferencedPersons() {

mongoTemplate.dropCollection(User.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* 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;
import org.springframework.data.mongodb.core.query.Criteria;

import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;

/**
* Unit tests for {@link OutOperation}.
*
* @author Nikolay Bogdanov
*/
public class OutOperationUnitTest {

@Test(expected = IllegalArgumentException.class)
public void shouldOutBeTheLastOperation() {
newAggregation(
match(new Criteria()),
group("field1")
.count().as("totalCount"),
out("collection1"),
skip(100),
limit(50));
}

@Test(expected = IllegalArgumentException.class)
public void shouldCheckNPEInCreation() {
new OutOperation(null);
}
}