Add support for $expMovingAvg aggregation operator.
The SpEL support for this one is missing due to the differing argument map (N, alpha). Closes: #3718 Original pull request: #3744.
This commit is contained in:
committed by
Mark Paluch
parent
dbfd4e5c62
commit
f3e067f59f
@@ -199,11 +199,61 @@ public class AccumulatorOperators {
|
||||
: CovarianceSamp.covarianceSampOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link ExpMovingAvgBuilder} that to build {@link AggregationExpression expMovingAvg} that calculates
|
||||
* the exponential moving average of numeric values
|
||||
*
|
||||
* @return new instance of {@link ExpMovingAvg}.
|
||||
* @since 3.3
|
||||
*/
|
||||
public ExpMovingAvgBuilder expMovingAvg() {
|
||||
|
||||
ExpMovingAvg expMovingAvg = usesFieldRef() ? ExpMovingAvg.expMovingAvgOf(fieldReference)
|
||||
: ExpMovingAvg.expMovingAvgOf(expression);
|
||||
return new ExpMovingAvgBuilder() {
|
||||
|
||||
@Override
|
||||
public ExpMovingAvg historicalDocuments(int numberOfHistoricalDocuments) {
|
||||
return expMovingAvg.n(numberOfHistoricalDocuments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpMovingAvg alpha(double exponentialDecayValue) {
|
||||
return expMovingAvg.alpha(exponentialDecayValue);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private boolean usesFieldRef() {
|
||||
return fieldReference != null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for {@link ExpMovingAvg}.
|
||||
*
|
||||
* @since 3.3
|
||||
*/
|
||||
public interface ExpMovingAvgBuilder {
|
||||
|
||||
/**
|
||||
* Define the number of historical documents with significant mathematical weight.
|
||||
*
|
||||
* @param numberOfHistoricalDocuments
|
||||
* @return new instance of {@link ExpMovingAvg}.
|
||||
*/
|
||||
ExpMovingAvg historicalDocuments(int numberOfHistoricalDocuments);
|
||||
|
||||
/**
|
||||
* Define the exponential decay value.
|
||||
*
|
||||
* @param exponentialDecayValue
|
||||
* @return new instance of {@link ExpMovingAvg}.
|
||||
*/
|
||||
ExpMovingAvg alpha(double exponentialDecayValue);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $sum}.
|
||||
*
|
||||
@@ -835,4 +885,65 @@ public class AccumulatorOperators {
|
||||
return "$covarianceSamp";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ExpMovingAvg} calculates the exponential moving average of numeric values.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 3.3
|
||||
*/
|
||||
public static class ExpMovingAvg extends AbstractAggregationExpression {
|
||||
|
||||
private ExpMovingAvg(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ExpMovingAvg} by defining the field holding the value to be used as input.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return new instance of {@link ExpMovingAvg}.
|
||||
*/
|
||||
public static ExpMovingAvg expMovingAvgOf(String fieldReference) {
|
||||
return new ExpMovingAvg(Collections.singletonMap("input", Fields.field(fieldReference)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ExpMovingAvg} by defining the {@link AggregationExpression expression} to compute the value
|
||||
* to be used as input.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return new instance of {@link ExpMovingAvg}.
|
||||
*/
|
||||
public static ExpMovingAvg expMovingAvgOf(AggregationExpression expression) {
|
||||
return new ExpMovingAvg(Collections.singletonMap("input", expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the number of historical documents with significant mathematical weight. <br />
|
||||
* Specify either {@link #n(int) N} or {@link #alpha(double) aplha}. Not both!
|
||||
*
|
||||
* @param numberOfHistoricalDocuments
|
||||
* @return new instance of {@link ExpMovingAvg}.
|
||||
*/
|
||||
public ExpMovingAvg n/*umber of historical documents*/(int numberOfHistoricalDocuments) {
|
||||
return new ExpMovingAvg(append("N", numberOfHistoricalDocuments));
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the exponential decay value. <br />
|
||||
* Specify either {@link #alpha(double) aplha} or {@link #n(int) N}. Not both!
|
||||
*
|
||||
* @param exponentialDecayValue
|
||||
* @return new instance of {@link ExpMovingAvg}.
|
||||
*/
|
||||
public ExpMovingAvg alpha(double exponentialDecayValue) {
|
||||
return new ExpMovingAvg(append("alpha", exponentialDecayValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$expMovingAvg";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.springframework.data.mongodb.core.aggregation.AccumulatorOperators.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
@@ -46,7 +47,7 @@ class AccumulatorOperatorsUnitTests {
|
||||
|
||||
assertThat(AccumulatorOperators.valueOf(Year.yearOf("birthdate")).covariancePop("midichlorianCount")
|
||||
.toDocument(TestAggregationContext.contextFor(Jedi.class)))
|
||||
.isEqualTo(new Document("$covariancePop", Arrays.asList(new Document("$year", "$birthdate"), "$force")));
|
||||
.isEqualTo(new Document("$covariancePop", Arrays.asList(new Document("$year", "$birthdate"), "$force")));
|
||||
}
|
||||
|
||||
@Test // GH-3712
|
||||
@@ -54,7 +55,7 @@ class AccumulatorOperatorsUnitTests {
|
||||
|
||||
assertThat(AccumulatorOperators.valueOf("balance").covarianceSamp("midichlorianCount")
|
||||
.toDocument(TestAggregationContext.contextFor(Jedi.class)))
|
||||
.isEqualTo(new Document("$covarianceSamp", Arrays.asList("$balance", "$force")));
|
||||
.isEqualTo(new Document("$covarianceSamp", Arrays.asList("$balance", "$force")));
|
||||
}
|
||||
|
||||
@Test // GH-3712
|
||||
@@ -62,7 +63,21 @@ class AccumulatorOperatorsUnitTests {
|
||||
|
||||
assertThat(AccumulatorOperators.valueOf(Year.yearOf("birthdate")).covarianceSamp("midichlorianCount")
|
||||
.toDocument(TestAggregationContext.contextFor(Jedi.class)))
|
||||
.isEqualTo(new Document("$covarianceSamp", Arrays.asList(new Document("$year", "$birthdate"), "$force")));
|
||||
.isEqualTo(new Document("$covarianceSamp", Arrays.asList(new Document("$year", "$birthdate"), "$force")));
|
||||
}
|
||||
|
||||
@Test // GH-3718
|
||||
void rendersExpMovingAvgWithNumberOfHistoricDocuments() {
|
||||
|
||||
assertThat(valueOf("price").expMovingAvg().historicalDocuments(2).toDocument(Aggregation.DEFAULT_CONTEXT))
|
||||
.isEqualTo(Document.parse("{ $expMovingAvg: { input: \"$price\", N: 2 } }"));
|
||||
}
|
||||
|
||||
@Test // GH-3718
|
||||
void rendersExpMovingAvgWithAlpha() {
|
||||
|
||||
assertThat(valueOf("price").expMovingAvg().alpha(0.75).toDocument(Aggregation.DEFAULT_CONTEXT))
|
||||
.isEqualTo(Document.parse("{ $expMovingAvg: { input: \"$price\", alpha: 0.75 } }"));
|
||||
}
|
||||
|
||||
static class Jedi {
|
||||
@@ -71,8 +86,7 @@ class AccumulatorOperatorsUnitTests {
|
||||
|
||||
Date birthdate;
|
||||
|
||||
@Field("force")
|
||||
Integer midichlorianCount;
|
||||
@Field("force") Integer midichlorianCount;
|
||||
|
||||
Integer balance;
|
||||
}
|
||||
|
||||
@@ -2503,7 +2503,7 @@ At the time of this writing, we provide support for the following Aggregation Op
|
||||
| `setEquals`, `setIntersection`, `setUnion`, `setDifference`, `setIsSubset`, `anyElementTrue`, `allElementsTrue`
|
||||
|
||||
| Group/Accumulator Aggregation Operators
|
||||
| `addToSet`, `covariancePop`, `covarianceSamp`, `first`, `last`, `max`, `min`, `avg`, `push`, `sum`, `(*count)`, `stdDevPop`, `stdDevSamp`
|
||||
| `addToSet`, `covariancePop`, `covarianceSamp`, `expMovingAvg`, `first`, `last`, `max`, `min`, `avg`, `push`, `sum`, `(*count)`, `stdDevPop`, `stdDevSamp`
|
||||
|
||||
| Arithmetic Aggregation Operators
|
||||
| `abs`, `add` (*via `plus`), `ceil`, `divide`, `exp`, `floor`, `ln`, `log`, `log10`, `mod`, `multiply`, `pow`, `round`, `sqrt`, `subtract` (*via `minus`), `trunc`
|
||||
|
||||
Reference in New Issue
Block a user