Add support for $derivative aggregation operator.

Closes: #3716
Original pull request: #3742.
This commit is contained in:
Christoph Strobl
2021-07-22 14:08:06 +02:00
committed by Mark Paluch
parent 75b5a548b6
commit 82b33331fc
4 changed files with 68 additions and 0 deletions

View File

@@ -26,7 +26,9 @@ import org.springframework.data.mongodb.core.aggregation.AccumulatorOperators.Mi
import org.springframework.data.mongodb.core.aggregation.AccumulatorOperators.StdDevPop;
import org.springframework.data.mongodb.core.aggregation.AccumulatorOperators.StdDevSamp;
import org.springframework.data.mongodb.core.aggregation.AccumulatorOperators.Sum;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Gateway to {@literal Arithmetic} aggregation operations that perform math operations on numbers.
@@ -591,6 +593,31 @@ public class ArithmeticOperators {
return round().place(place);
}
/**
* Creates new {@link AggregationExpression} that calculates the mathematical derivative value.
*
* @return new instance of {@link Derivative}.
* @since 3.3
*/
public Derivative derivative() {
return derivative(null);
}
/**
* Creates new {@link AggregationExpression} that calculates the mathematical derivative value.
*
* @param unit The time unit ({@literal week, day, hour, minute, second, millisecond}) to apply can be
* {@literal null}.
* @return new instance of {@link Derivative}.
* @since 3.3
*/
public Derivative derivative(@Nullable String unit) {
Derivative derivative = usesFieldRef() ? Derivative.derivativeOf(fieldReference)
: Derivative.derivativeOf(expression);
return StringUtils.hasText(unit) ? derivative.unit(unit) : derivative;
}
private boolean usesFieldRef() {
return fieldReference != null;
}
@@ -1724,4 +1751,32 @@ public class ArithmeticOperators {
return "$round";
}
}
public static class Derivative extends AbstractAggregationExpression {
private Derivative(Object value) {
super(value);
}
public static Derivative derivativeOf(String fieldReference) {
return new Derivative(Collections.singletonMap("input", Fields.field(fieldReference)));
}
public static Derivative derivativeOf(AggregationExpression expression) {
return new Derivative(Collections.singletonMap("input", expression));
}
public static Derivative derivativeOfValue(Number value) {
return new Derivative(Collections.singletonMap("input", value));
}
public Derivative unit(String unit) {
return new Derivative(append("unit", unit));
}
@Override
protected String getMongoMethod() {
return "$derivative";
}
}
}

View File

@@ -91,6 +91,7 @@ public class MethodReferenceNode extends ExpressionNode {
map.put("subtract", arrayArgRef().forOperator("$subtract"));
map.put("trunc", singleArgRef().forOperator("$trunc"));
map.put("round", arrayArgRef().forOperator("$round"));
map.put("derivative", mapArgRef().forOperator("$derivative").mappingParametersTo("input", "unit"));
// STRING OPERATORS
map.put("concat", arrayArgRef().forOperator("$concat"));

View File

@@ -59,4 +59,11 @@ public class ArithmeticOperatorsUnitTests {
.toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo(new Document("$round", Arrays.asList("$field", new Document("$first", "$source"))));
}
@Test // GH-3716
void rendersDerivativeCorrectly() {
assertThat(valueOf("miles").derivative("hour").toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo(Document.parse("{ $derivative: { input: \"$miles\", unit: \"hour\" } }"));
}
}

View File

@@ -989,6 +989,11 @@ public class SpelExpressionTransformerUnitTests {
}
@Nullable
@Test // GH-3716
void shouldRenderDerivative() {
assertThat(transform("derivative(miles, 'hour')")).isEqualTo(Document.parse("{ \"$derivative\" : { input : '$miles', unit : 'hour'} }"));
}
private Object transform(String expression, Object... params) {
Object result = transformer.transform(expression, Aggregation.DEFAULT_CONTEXT, params);
return result == null ? null : (!(result instanceof org.bson.Document) ? result.toString() : result);