Add support for $bottomN aggregation operator.

Closes #4139
Original pull request: #4182.
This commit is contained in:
Christoph Strobl
2022-09-22 10:55:19 +02:00
committed by Mark Paluch
parent 052cfdfd45
commit 59464f3b3c
5 changed files with 59 additions and 8 deletions

View File

@@ -38,9 +38,14 @@ public class SelectionOperators {
super(value);
}
/**
* In case a limit value ({@literal n}) is present {@literal $bottomN} is used instead of {@literal $bottom}.
*
* @return
*/
@Override
protected String getMongoMethod() {
return "$bottom";
return get("n") == null ? "$bottom" : "$bottomN";
}
/**
@@ -50,6 +55,31 @@ public class SelectionOperators {
return new Bottom(Collections.emptyMap());
}
/**
* Limits the number of returned elements to the given value.
*
* @param numberOfResults
* @return new instance of {@link Bottom}.
*/
public Bottom limit(int numberOfResults) {
return limit((Object) numberOfResults);
}
/**
* Limits the number of returned elements to the value defined by the given {@link AggregationExpression
* expression}.
*
* @param expression must not be {@literal null}.
* @return new instance of {@link Bottom}.
*/
public Bottom limit(AggregationExpression expression) {
return limit((Object) expression);
}
private Bottom limit(Object value) {
return new Bottom(append("n", value));
}
/**
* Define result ordering.
*

View File

@@ -212,6 +212,10 @@ public class MethodReferenceNode extends ExpressionNode {
// OBJECT OPERATORS
map.put("objectToArray", singleArgRef().forOperator("$objectToArray"));
map.put("mergeObjects", arrayArgRef().forOperator("$mergeObjects"));
map.put("bottom", mapArgRef().forOperator("$bottom") //
.mappingParametersTo("output", "sortBy"));
map.put("bottomN", mapArgRef().forOperator("$bottomN") //
.mappingParametersTo("n", "output", "sortBy"));
// CONVERT OPERATORS
map.put("convert", mapArgRef().forOperator("$convert") //
@@ -226,9 +230,6 @@ public class MethodReferenceNode extends ExpressionNode {
map.put("toString", singleArgRef().forOperator("$toString"));
map.put("degreesToRadians", singleArgRef().forOperator("$degreesToRadians"));
// SELECT OPERATORS
map.put("bottom", mapArgRef().forOperator("$bottom") //
.mappingParametersTo("output", "sortBy"));
FUNCTIONS = Collections.unmodifiableMap(map);
}

View File

@@ -71,6 +71,24 @@ class SelectionOperatorUnitTests {
"""));
}
@Test // GH-4139
void bottomNRenderedCorrectly() {
Document document = SelectionOperators.Bottom.bottom().output(Fields.fields("playerId", "score"))
.sortBy(Sort.by(Direction.DESC, "score")).limit(3).toDocument(Aggregation.DEFAULT_CONTEXT);
assertThat(document).isEqualTo(Document.parse("""
{
$bottomN:
{
n : 3,
output: [ "$playerId", "$score" ],
sortBy: { "score": -1 }
}
}
"""));
}
static class Player {
@Field("player_id") String playerId;

View File

@@ -1179,6 +1179,11 @@ public class SpelExpressionTransformerUnitTests {
assertThat(transform("bottom(new String[]{\"$playerId\", \"$score\" }, { \"score\" : -1 })")).isEqualTo("{ $bottom : { output: [ \"$playerId\", \"$score\" ], sortBy: { \"score\": -1 }}}");
}
@Test // GH-4139
void shouldRenderBottomN() {
assertThat(transform("bottomN(3, new String[]{\"$playerId\", \"$score\" }, { \"score\" : -1 })")).isEqualTo("{ $bottomN : { n : 3, output: [ \"$playerId\", \"$score\" ], sortBy: { \"score\": -1 }}}");
}
private Document transform(String expression, Object... params) {
return (Document) transformer.transform(expression, Aggregation.DEFAULT_CONTEXT, params);
}