diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AddFieldsOperation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AddFieldsOperation.java index 3f3dd125d1..186d420242 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AddFieldsOperation.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AddFieldsOperation.java @@ -19,7 +19,13 @@ import java.util.LinkedHashMap; import java.util.Map; +import org.bson.Document; import org.springframework.data.mongodb.core.aggregation.AddFieldsOperation.AddFieldsOperationBuilder.ValueAppender; +import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField; +import org.springframework.data.mongodb.core.aggregation.GroupOperation.Keyword; +import org.springframework.data.mongodb.core.aggregation.GroupOperation.Operation; +import org.springframework.data.mongodb.core.aggregation.ProjectionOperation.ProjectionOperationBuilder; + import org.springframework.lang.Nullable; /** @@ -123,7 +129,7 @@ private AddFieldsOperationBuilder() { private AddFieldsOperationBuilder(Map source) { this.valueMap = new LinkedHashMap<>(source); } - + public AddFieldsOperationBuilder addFieldWithValue(String field, @Nullable Object value) { return addField(field).withValue(value); } @@ -131,6 +137,8 @@ public AddFieldsOperationBuilder addFieldWithValue(String field, @Nullable Objec public AddFieldsOperationBuilder addFieldWithValueOf(String field, Object value) { return addField(field).withValueOf(value); } + + /** * Define the field to add. @@ -168,7 +176,7 @@ public AddFieldsOperationBuilder withValueOfExpression(String operation, Object. public AddFieldsOperation build() { return new AddFieldsOperation(valueMap); } - + /** * @author Christoph Strobl * @since 3.0 @@ -201,4 +209,6 @@ public interface ValueAppender { AddFieldsOperationBuilder withValueOfExpression(String operation, Object... values); } } + + } 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 cecc8f2554..55964bab93 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 @@ -498,7 +498,17 @@ public static MatchOperation match(Criteria criteria) { public static MatchOperation match(CriteriaDefinition criteria) { return new MatchOperation(criteria); } - + + /** + * Creates a new {@link MatchOperation} + * + * @return new instance of {@link MatchOperation}. + * @since 1.10 + */ + public static MatchOperation match() { + return new MatchOperation(); + } + /** * Creates a new {@link GeoNearOperation} instance from the given {@link NearQuery} and the {@code distanceField}. The * {@code distanceField} defines output field that contains the calculated distance. diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/EvaluationOperators.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/EvaluationOperators.java new file mode 100644 index 0000000000..0fb8e25fab --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/EvaluationOperators.java @@ -0,0 +1,109 @@ +package org.springframework.data.mongodb.core.aggregation; + +import org.springframework.util.Assert; + +public class EvaluationOperators { + + /** + * Take the value resulting from the given fieldReference. + * + * @param fieldReference must not be {@literal null}. + * @return new instance of {@link EvaluationOperatorFactory}. + */ + public static EvaluationOperatorFactory valueOf(String fieldReference) { + return new EvaluationOperatorFactory(fieldReference); + } + + /** + * Take the value resulting from the given {@link AggregationExpression}. + * + * @param expression must not be {@literal null}. + * @return new instance of {@link EvaluationOperatorFactory}. + */ + public static EvaluationOperatorFactory valueOf(AggregationExpression expression) { + return new EvaluationOperatorFactory(expression); + } + + public static class EvaluationOperatorFactory { + + private final String fieldReference; + private final AggregationExpression expression; + + /** + * Creates new {@link EvaluationOperatorFactory} for given {@literal fieldReference}. + * + * @param fieldReference must not be {@literal null}. + */ + public EvaluationOperatorFactory(String fieldReference) { + + Assert.notNull(fieldReference, "FieldReference must not be null!"); + this.fieldReference = fieldReference; + this.expression = null; + } + + + /** + * Creates new {@link EvaluationOperatorFactory} for given {@link AggregationExpression}. + * + * @param expression must not be {@literal null}. + */ + public EvaluationOperatorFactory(AggregationExpression expression) { + + Assert.notNull(expression, "Expression must not be null!"); + this.fieldReference = null; + this.expression = expression; + } + + /** + * Creates new {@link AggregationExpression} that is a valid aggregation expression. + * + * @return new instance of {@link Expr}. + */ + public Expr expr() { + return usesFieldRef() ? Expr.valueOf(fieldReference) : Expr.valueOf(expression); + } + + + public static class Expr extends AbstractAggregationExpression { + + private Expr(Object value) { + super(value); + } + + @Override + protected String getMongoMethod() { + return "$expr"; + } + + /** + * Creates new {@link Expr}. + * + * @param fieldReference must not be {@literal null}. + * @return new instance of {@link Expr}. + */ + public static Expr valueOf(String fieldReference) { + + Assert.notNull(fieldReference, "FieldReference must not be null!"); + return new Expr(Fields.field(fieldReference)); + } + + /** + * Creates new {@link Expr}. + * + * @param expression must not be {@literal null}. + * @return new instance of {@link Expr}. + */ + public static Expr valueOf(AggregationExpression expression) { + + Assert.notNull(expression, "Expression must not be null!"); + return new Expr(expression); + } + + } + + private boolean usesFieldRef() { + return fieldReference != null; + } + } + +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/MatchOperation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/MatchOperation.java index c9d83ae6c8..c2796aaa03 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/MatchOperation.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/MatchOperation.java @@ -16,6 +16,7 @@ package org.springframework.data.mongodb.core.aggregation; import org.bson.Document; +import org.springframework.data.mongodb.core.aggregation.EvaluationOperators.EvaluationOperatorFactory.Expr; import org.springframework.data.mongodb.core.query.CriteriaDefinition; import org.springframework.util.Assert; @@ -36,7 +37,16 @@ public class MatchOperation implements AggregationOperation { private final CriteriaDefinition criteriaDefinition; - + private final AggregationExpression expression; + + /** + * Creates a new {@link MatchOperation} + */ + public MatchOperation() { + this.criteriaDefinition = null; + this.expression = null; + } + /** * Creates a new {@link MatchOperation} for the given {@link CriteriaDefinition}. * @@ -46,14 +56,39 @@ public MatchOperation(CriteriaDefinition criteriaDefinition) { Assert.notNull(criteriaDefinition, "Criteria must not be null!"); this.criteriaDefinition = criteriaDefinition; + this.expression = null; } - + + /** + * Creates a new {@link MatchOperation} for the given {@link Expression}. + * + * @param criteriaDefinition must not be {@literal null}. + */ + private MatchOperation(Expr expression) { + Assert.notNull(expression, "Expression must not be null!"); + this.criteriaDefinition = null; + this.expression = expression; + } + + /** + * Creates a new {@link MatchOperation} for the given {@link AggregationExpression}. + * + * @param expression must not be {@literal null}. + */ + public MatchOperation withValueOf(AggregationExpression expression) { + Assert.notNull(expression, "Expression must not be null!"); + return new MatchOperation(EvaluationOperators.valueOf(expression).expr()); + } + /* * (non-Javadoc) * @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext) */ @Override public Document toDocument(AggregationOperationContext context) { + if(expression != null) { + return new Document(getOperator(), expression.toDocument()); + } return new Document(getOperator(), context.getMappedObject(criteriaDefinition.getCriteriaObject())); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperation.java index d2f173e90b..1879991ade 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperation.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperation.java @@ -1306,7 +1306,7 @@ public ProjectionOperationBuilder let(AggregationExpression valueExpression, Str public ProjectionOperationBuilder let(Collection variables, AggregationExpression in) { return this.operation.and(VariableOperators.Let.define(variables).andApply(in)); } - + private String getRequiredName() { Assert.state(name != null, "Projection field name must not be null!"); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ReplaceRootOperation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ReplaceRootOperation.java index c452ffb8ea..f6dca04f58 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ReplaceRootOperation.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ReplaceRootOperation.java @@ -21,6 +21,7 @@ import java.util.List; import org.bson.Document; +import org.springframework.data.mongodb.core.aggregation.AddFieldsOperation.AddFieldsOperationBuilder; import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField; import org.springframework.expression.spel.ast.Projection; import org.springframework.util.Assert; @@ -112,7 +113,8 @@ public ExposedFields getFields() { protected Replacement getReplacement() { return replacement; } - + + /** * Builder for {@link ReplaceRootOperation}. * diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/SetOperation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/SetOperation.java index 731668ed3c..6aecfd4563 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/SetOperation.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/SetOperation.java @@ -19,6 +19,7 @@ import java.util.LinkedHashMap; import java.util.Map; +import org.springframework.data.mongodb.core.aggregation.AddFieldsOperation.AddFieldsOperationBuilder; import org.springframework.data.mongodb.core.aggregation.SetOperation.FieldAppender.ValueAppender; import org.springframework.lang.Nullable; @@ -193,5 +194,7 @@ public interface ValueAppender { */ SetOperation withValueOfExpression(String operation, Object... values); } + + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AddFieldsOperationUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AddFieldsOperationUnitTests.java index b2f2bd611d..637c2d2585 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AddFieldsOperationUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AddFieldsOperationUnitTests.java @@ -126,6 +126,23 @@ void exposesFieldsCorrectly() { assertThat(fields.getField("computed")).isNotNull(); assertThat(fields.getField("does-not-exist")).isNull(); } + + @Test // DATAMONGO - 3729 + void rendersStdDevPopCorrectly() { + assertThat(AddFieldsOperation.builder().addField("totalQuiz") + .withValue(ArithmeticOperators.valueOf("quiz").stdDevPop()).build() + .toPipelineStages(contextFor(ScoresWrapper.class))).containsExactly( + Document.parse("{\"$addFields\" : {\"totalQuiz\": { \"$stdDevPop\" : \"$quiz\" } }}")); + } + + @Test // DATAMONGO - 3729 + void rendersStdDevSampCorrectly() { + assertThat(AddFieldsOperation.builder().addField("totalQuiz") + .withValue(ArithmeticOperators.valueOf("quiz").stdDevSamp()).build() + .toPipelineStages(contextFor(ScoresWrapper.class))) + .containsExactly(Document.parse( + "{\"$addFields\" : {\"totalQuiz\": { \"$stdDevSamp\" : \"$quiz\" } }}")); + } private static AggregationOperationContext contextFor(@Nullable Class type) { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationUnitTests.java index 37aeb5b2cf..087613cc31 100755 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationUnitTests.java @@ -133,6 +133,7 @@ void unwindOperationWithPreserveNullShouldBuildCorrectClause() { .doesNotContainKey("$unwind.includeArrayIndex") // .containsEntry("$unwind.preserveNullAndEmptyArrays", true); } + @Test // DATAMONGO-1550 void replaceRootOperationShouldBuildCorrectClause() { @@ -145,7 +146,7 @@ void replaceRootOperationShouldBuildCorrectClause() { Document unwind = ((List) agg.get("pipeline")).get(0); assertThat(unwind).containsEntry("$replaceRoot.newRoot", new Document("field", "value")); } - + @Test // DATAMONGO-753 void matchOperationShouldNotChangeAvailableFields() { @@ -155,7 +156,7 @@ void matchOperationShouldNotChangeAvailableFields() { project("a", "b") // b should still be available ).toDocument("foo", Aggregation.DEFAULT_CONTEXT); } - + @Test // DATAMONGO-788 void referencesToGroupIdsShouldBeRenderedAsReferences() { @@ -597,7 +598,7 @@ void projectOnIdIsAlwaysValid() { assertThat(extractPipelineElement(target, 1, "$project")).isEqualTo(Document.parse(" { \"_id\" : \"$_id\" }")); } - + private Document extractPipelineElement(Document agg, int index, String operation) { List pipeline = (List) agg.get("pipeline"); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/MatchOperationUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/MatchOperationUnitTests.java new file mode 100644 index 0000000000..04d3824de1 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/MatchOperationUnitTests.java @@ -0,0 +1,26 @@ +package org.springframework.data.mongodb.core.aggregation; + +import static org.assertj.core.api.Assertions.*; + +import org.bson.Document; +import org.junit.jupiter.api.Test; + +class MatchOperationUnitTests { + + @Test // DATAMONGO - 3729 + public void shouldRenderStdDevPopCorrectly() { + MatchOperation operation = Aggregation.match().withValueOf(ArithmeticOperators.valueOf("quiz").stdDevPop()); + assertThat(operation.toDocument(Aggregation.DEFAULT_CONTEXT)). + isEqualTo(Document.parse("{ $match: { \"$expr\" : { \"$stdDevPop\" : \"$quiz\" } } } ")); + + } + + @Test // DATAMONGO - 3729 + public void shouldRenderStdDevSampCorrectly() { + MatchOperation operation = Aggregation.match().withValueOf(ArithmeticOperators.valueOf("quiz").stdDevSamp()); + assertThat(operation.toDocument(Aggregation.DEFAULT_CONTEXT)). + isEqualTo(Document.parse("{ $match: { \"$expr\" : { \"$stdDevSamp\" : \"$quiz\" } } } ")); + + } + +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ReplaceRootOperationUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ReplaceRootOperationUnitTests.java index e97e1ff018..4677b56dfa 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ReplaceRootOperationUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ReplaceRootOperationUnitTests.java @@ -19,7 +19,7 @@ import org.bson.Document; import org.junit.jupiter.api.Test; - +import org.springframework.data.mongodb.core.aggregation.AddFieldsOperationUnitTests.ScoresWrapper; import org.springframework.data.mongodb.core.aggregation.ReplaceRootOperation.ReplaceRootDocumentOperation; /** @@ -99,4 +99,22 @@ public void shouldNotExposeFields() { assertThat(operation.getFields().exposesNoFields()).isTrue(); assertThat(operation.getFields().exposesSingleFieldOnly()).isFalse(); } + + @Test // DATAMONGO - 3729 + void shouldRendersStdDevPopCorrectly() { + ReplaceRootOperation operation = ReplaceRootOperation.builder() + .withValueOf(ArithmeticOperators.valueOf("quiz").stdDevPop()); + Document dbObject = operation.toDocument(Aggregation.DEFAULT_CONTEXT); + assertThat(dbObject) + .isEqualTo(Document.parse("{\"$replaceRoot\" : {\"newRoot\": { \"$stdDevPop\" : \"$quiz\" } }}")); + } + + @Test // DATAMONGO - 3729 + void shouldRendersStdDevSampCorrectly() { + ReplaceRootOperation operation = ReplaceRootOperation.builder() + .withValueOf(ArithmeticOperators.valueOf("quiz").stdDevSamp()); + Document dbObject = operation.toDocument(Aggregation.DEFAULT_CONTEXT); + assertThat(dbObject).isEqualTo(Document.parse( + "{\"$replaceRoot\" : {\"newRoot\": { \"$stdDevSamp\" : \"$quiz\" } }}")); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ReplaceWithOperationUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ReplaceWithOperationUnitTests.java index 8f8b5c9dd1..666d7a4363 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ReplaceWithOperationUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ReplaceWithOperationUnitTests.java @@ -19,6 +19,7 @@ import org.bson.Document; import org.junit.jupiter.api.Test; +import org.springframework.data.mongodb.core.aggregation.ReplaceRootOperation.ReplaceRootDocumentOperation; /** * Unit tests for {@link ReplaceRootOperation}. @@ -54,4 +55,21 @@ public void shouldRenderExpressionCorrectly() { assertThat(dbObject).isEqualTo(Document.parse("{ $replaceWith : { " + "$map : { input : \"$array\" , as : \"element\" , in : { $multiply : [ \"$$element\" , 10]} } " + "} }")); } + + @Test // DATAMONGO - 3729 + void shouldRendersStdDevPopCorrectly() { + ReplaceWithOperation operation = ReplaceWithOperation + .replaceWithValueOf(ArithmeticOperators.valueOf("quiz").stdDevPop()); + Document dbObject = operation.toDocument(Aggregation.DEFAULT_CONTEXT); + assertThat(dbObject).isEqualTo(Document.parse("{\"$replaceWith\" : { \"$stdDevPop\" : \"$quiz\" } }")); + } + + @Test // DATAMONGO - 3729 + void shouldRendersStdDevSampCorrectly() { + ReplaceWithOperation operation = ReplaceWithOperation + .replaceWithValueOf(ArithmeticOperators.valueOf("quiz").stdDevSamp()); + Document dbObject = operation.toDocument(Aggregation.DEFAULT_CONTEXT); + assertThat(dbObject).isEqualTo(Document.parse( + "{\"$replaceWith\" : { \"$stdDevSamp\" : \"$quiz\" } }")); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SetOperationUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SetOperationUnitTests.java index b90b049da1..f146ae55c2 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SetOperationUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SetOperationUnitTests.java @@ -21,6 +21,7 @@ import org.bson.Document; import org.junit.jupiter.api.Test; +import org.springframework.data.mongodb.core.aggregation.AddFieldsOperationUnitTests.ScoresWrapper; import org.springframework.data.mongodb.core.convert.MappingMongoConverter; import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver; import org.springframework.data.mongodb.core.convert.QueryMapper; @@ -104,6 +105,21 @@ void rendersTargetValueExpressionCorrectly() { .toPipelineStages(contextFor(Scores.class))) .containsExactly(Document.parse("{\"$set\" : {\"totalHomework\": { \"$sum\" : \"$homework\" }}}")); } + + @Test // DATAMONGO - 3729 + void rendersStdDevPopCorrectly() { + assertThat(SetOperation.builder().set("totalQuiz").toValueOf(ArithmeticOperators.valueOf("quiz").stdDevPop()) + .toPipelineStages(contextFor(ScoresWrapper.class))).containsExactly( + Document.parse("{\"$set\" : {\"totalQuiz\": { \"$stdDevPop\" : \"$quiz\" } }}")); + } + + @Test // DATAMONGO - 3729 + void rendersStdDevSampCorrectly() { + assertThat( + SetOperation.builder().set("totalQuiz").toValueOf(ArithmeticOperators.valueOf("quiz").stdDevSamp()) + .toPipelineStages(contextFor(ScoresWrapper.class))).containsExactly( + Document.parse("{\"$set\" : {\"totalQuiz\": { \"$stdDevSamp\" : \"$quiz\" } }}")); + } @Test // DATAMONGO-2331 void exposesFieldsCorrectly() { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SetWindowFieldsOperationUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SetWindowFieldsOperationUnitTests.java index 62b0f4dffc..9d1865df2e 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SetWindowFieldsOperationUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SetWindowFieldsOperationUnitTests.java @@ -86,6 +86,34 @@ void rendersMuiltipleOutputFields() { assertThat(document).isEqualTo(Document.parse( "{ $setWindowFields: { output: { f1 : { $sum: \"$quantity\", window: { documents: [ \"unbounded\", \"current\" ] } }, f2 : { $avg: \"$quantity\", window: { documents: [ -1, 0 ] } } } } }")); } + + @Test // DATAMONGO - 3729 + void rendersOutputFieldsWithStdDevPopOperator() { + + SetWindowFieldsOperation setWindowFieldsOperation = SetWindowFieldsOperation.builder() // + .output(ArithmeticOperators.valueOf("qty").stdDevPop()) + .within(Windows.documents().fromUnbounded().toCurrent().build()) // + .as("f1") // + .build(); // + + Document document = setWindowFieldsOperation.toDocument(contextFor(CakeSale.class)); + assertThat(document).isEqualTo(Document.parse( + "{ $setWindowFields: { output: { f1 : { $stdDevPop: \"$quantity\", window: { documents: [ \"unbounded\", \"current\" ] } } } } }")); + } + + @Test // DATAMONGO - 3729 + void rendersOutputFieldsWithStdDevSampOperator() { + + SetWindowFieldsOperation setWindowFieldsOperation = SetWindowFieldsOperation.builder() // + .output(ArithmeticOperators.valueOf("qty").stdDevSamp()) + .within(Windows.documents().fromUnbounded().toCurrent().build()) // + .as("f1") // + .build(); // + + Document document = setWindowFieldsOperation.toDocument(contextFor(CakeSale.class)); + assertThat(document).isEqualTo(Document.parse( + "{ $setWindowFields: { output: { f1 : { $stdDevSamp: \"$quantity\", window: { documents: [ \"unbounded\", \"current\" ] } } } } }")); + } private static AggregationOperationContext contextFor(@Nullable Class type) {