DATAMONGO-1549 - Add $count aggregation stage.
We now support the $count stage in aggregation pipelines.
newAggregation(
match(where("hotelCode").is("0360")),
count().as("documents"));
Original Pull Request: #422
This commit is contained in:
committed by
Christoph Strobl
parent
7b49b120e3
commit
cab35759db
@@ -23,6 +23,7 @@ import java.util.List;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.mongodb.core.aggregation.CountOperation.CountOperationBuilder;
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.DirectFieldReference;
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
|
||||
@@ -396,6 +397,16 @@ public class Aggregation {
|
||||
return new LookupOperation(from, localField, foreignField, as);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link CountOperationBuilder}.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
* @since 1.10
|
||||
*/
|
||||
public static CountOperationBuilder count() {
|
||||
return new CountOperationBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Fields} instance for the given field names.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* Encapsulates the aggregation framework {@code $count}-operation.
|
||||
* <p>
|
||||
* We recommend to use the static factory method {@link Aggregation#count()} instead of creating instances of this
|
||||
* class directly.
|
||||
*
|
||||
* @see https://docs.mongodb.com/manual/reference/operator/aggregation/count/#pipe._S_count
|
||||
* @author Mark Paluch
|
||||
* @since 1.10
|
||||
*/
|
||||
public class CountOperation implements FieldsExposingAggregationOperation {
|
||||
|
||||
private final String fieldName;
|
||||
|
||||
/**
|
||||
* Creates a new {@link CountOperation} given the {@link fieldName} field name.
|
||||
*
|
||||
* @param asFieldName must not be {@literal null} or empty.
|
||||
*/
|
||||
public CountOperation(String fieldName) {
|
||||
|
||||
Assert.hasText(fieldName, "Field name must not be null or empty!");
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
/* (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("$count", fieldName);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation#getFields()
|
||||
*/
|
||||
@Override
|
||||
public ExposedFields getFields() {
|
||||
return ExposedFields.from(new ExposedField(fieldName, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for {@link CountOperation}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public static class CountOperationBuilder {
|
||||
|
||||
/**
|
||||
* Returns the finally to be applied {@link CountOperation} with the given alias.
|
||||
*
|
||||
* @param fieldName must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
public CountOperation as(String fieldName) {
|
||||
return new CountOperation(fieldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,6 +100,7 @@ public class AggregationTests {
|
||||
private static final Version TWO_DOT_FOUR = new Version(2, 4);
|
||||
private static final Version TWO_DOT_SIX = new Version(2, 6);
|
||||
private static final Version THREE_DOT_TWO = new Version(3, 2);
|
||||
private static final Version THREE_DOT_FOUR = new Version(3, 4);
|
||||
|
||||
private static boolean initialized = false;
|
||||
|
||||
@@ -1298,6 +1299,30 @@ public class AggregationTests {
|
||||
assertThat(result.getMappedResults(), hasSize(2));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1549
|
||||
*/
|
||||
@Test
|
||||
public void shouldApplyCountCorrectly() {
|
||||
|
||||
assumeTrue(mongoVersion.isGreaterThanOrEqualTo(THREE_DOT_FOUR));
|
||||
|
||||
mongoTemplate.save(new Reservation("0123", "42", 100));
|
||||
mongoTemplate.save(new Reservation("0360", "43", 200));
|
||||
mongoTemplate.save(new Reservation("0360", "44", 300));
|
||||
|
||||
Aggregation agg = newAggregation( //
|
||||
count().as("documents"), //
|
||||
project("documents") //
|
||||
.andExpression("documents * 2").as("twice"));
|
||||
AggregationResults<DBObject> result = mongoTemplate.aggregate(agg, Reservation.class, DBObject.class);
|
||||
|
||||
assertThat(result.getMappedResults(), hasSize(1));
|
||||
|
||||
DBObject dbObject = result.getMappedResults().get(0);
|
||||
assertThat(dbObject, isBsonObject().containing("documents", 3).containing("twice", 6));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-975
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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 static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.util.JSON;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link CountOperation}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class CountOperationUnitTests {
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1549
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsEmptyFieldName() {
|
||||
new CountOperation("");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1549
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderCorrectly() {
|
||||
|
||||
CountOperation countOperation = new CountOperation("field");
|
||||
DBObject dbObject = countOperation.toDBObject(Aggregation.DEFAULT_CONTEXT);
|
||||
|
||||
assertThat(dbObject, is(JSON.parse("{$count : \"field\" }")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1549
|
||||
*/
|
||||
@Test
|
||||
public void countExposesFields() {
|
||||
|
||||
CountOperation countOperation = new CountOperation("field");
|
||||
|
||||
assertThat(countOperation.getFields().exposesNoFields(), is(false));
|
||||
assertThat(countOperation.getFields().exposesSingleFieldOnly(), is(true));
|
||||
assertThat(countOperation.getFields().getField("field"), notNullValue());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user