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 ff9ec46d1..fe8a0f968 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 @@ -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. * diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/CountOperation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/CountOperation.java new file mode 100644 index 000000000..ed4c274c2 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/CountOperation.java @@ -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. + *
+ * 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);
+ }
+ }
+}
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 d89d1a782..fffe2d304 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
@@ -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