diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/GroupOperation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/GroupOperation.java index 8f586fd75..b58ec4b24 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/GroupOperation.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/GroupOperation.java @@ -23,6 +23,7 @@ import java.util.List; import org.bson.Document; import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField; import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference; +import org.springframework.data.mongodb.core.aggregation.ScriptOperators.Accumulator; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -375,6 +376,17 @@ public class GroupOperation implements FieldsExposingAggregationOperation { return newBuilder(GroupOps.STD_DEV_POP, null, expr); } + /** + * Generates an {@link GroupOperationBuilder} for an {@code $accumulator}-expression. + * + * @param accumulator must not be {@literal null}. + * @return never {@literal null}. + * @since 1.10 + */ + public GroupOperationBuilder accumulate(Accumulator accumulator) { + return new GroupOperationBuilder(this, new Operation(accumulator)); + } + private GroupOperationBuilder newBuilder(Keyword keyword, @Nullable String reference, @Nullable Object value) { return new GroupOperationBuilder(this, new Operation(keyword, null, reference, value)); } @@ -465,12 +477,16 @@ public class GroupOperation implements FieldsExposingAggregationOperation { static class Operation implements AggregationOperation { - private final Keyword op; + private final @Nullable Keyword op; private final @Nullable String key; private final @Nullable String reference; private final @Nullable Object value; - public Operation(Keyword op, @Nullable String key, @Nullable String reference, @Nullable Object value) { + Operation(AggregationExpression expression) { + this(null, null, null, expression); + } + + public Operation(@Nullable Keyword op, @Nullable String key, @Nullable String reference, @Nullable Object value) { this.op = op; this.key = key; @@ -487,7 +503,12 @@ public class GroupOperation implements FieldsExposingAggregationOperation { } public Document toDocument(AggregationOperationContext context) { - return new Document(key, new Document(op.toString(), getValue(context))); + + Object value = getValue(context); + if(op == null && value instanceof Document) { + return new Document(key, value); + } + return new Document(key, new Document(op.toString(), value)); } public Object getValue(AggregationOperationContext context) { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/GroupOperationUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/GroupOperationUnitTests.java index 6239b3d10..3340e8119 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/GroupOperationUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/GroupOperationUnitTests.java @@ -23,7 +23,6 @@ import java.util.Arrays; import org.bson.Document; import org.junit.jupiter.api.Test; - import org.springframework.data.mongodb.core.DocumentTestUtils; import org.springframework.data.mongodb.core.query.Criteria; @@ -241,6 +240,20 @@ public class GroupOperationUnitTests { .isThrownBy(() -> Aggregation.group("username").sum((AggregationExpression) null)); } + @Test // DATAMONGO-2651 + void accumulatorShouldBeAllowedOnGroupOperation() { + + GroupOperation groupOperation = Aggregation.group("id") + .accumulate( + ScriptOperators.accumulatorBuilder().init("inti").accumulate("acc").merge("merge").finalize("finalize")) + .as("accumulated-value"); + + Document groupClause = extractDocumentFromGroupOperation(groupOperation); + Document accumulatedValue = DocumentTestUtils.getAsDocument(groupClause, "accumulated-value"); + + assertThat(accumulatedValue.get("$accumulator")).isNotNull(); + } + private Document extractDocumentFromGroupOperation(GroupOperation groupOperation) { Document document = groupOperation.toDocument(Aggregation.DEFAULT_CONTEXT); Document groupClause = DocumentTestUtils.getAsDocument(document, "$group");