Add support for $firstN aggregation operator.
Closes #4139 Original pull request: #4182.
This commit is contained in:
committed by
Mark Paluch
parent
59464f3b3c
commit
5525a4fbf9
@@ -122,4 +122,98 @@ public class SelectionOperators {
|
|||||||
return new Bottom(append("output", Arrays.asList(out)));
|
return new Bottom(append("output", Arrays.asList(out)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link AbstractAggregationExpression} to return the {@literal $firstN} elements.
|
||||||
|
*/
|
||||||
|
public static class First extends AbstractAggregationExpression {
|
||||||
|
|
||||||
|
protected First(Object value) {
|
||||||
|
super(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return new instance of {@link First}.
|
||||||
|
*/
|
||||||
|
public static First first() {
|
||||||
|
return new First(Collections.emptyMap()).limit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return new instance of {@link First}.
|
||||||
|
*/
|
||||||
|
public static First first(int numberOfResults) {
|
||||||
|
return new First(Collections.emptyMap()).limit(numberOfResults);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Limits the number of returned elements to the given value.
|
||||||
|
*
|
||||||
|
* @param numberOfResults
|
||||||
|
* @return new instance of {@link Bottom}.
|
||||||
|
*/
|
||||||
|
public First 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 First limit(AggregationExpression expression) {
|
||||||
|
return limit((Object) expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
private First limit(Object value) {
|
||||||
|
return new First(append("n", value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the field to serve as source.
|
||||||
|
*
|
||||||
|
* @param fieldName must not be {@literal null}.
|
||||||
|
* @return new instance of {@link Bottom}.
|
||||||
|
*/
|
||||||
|
public First of(String fieldName) {
|
||||||
|
return input(fieldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the expression building the value to serve as source.
|
||||||
|
*
|
||||||
|
* @param expression must not be {@literal null}.
|
||||||
|
* @return new instance of {@link Bottom}.
|
||||||
|
*/
|
||||||
|
public First of(AggregationExpression expression) {
|
||||||
|
return input(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the field to serve as source.
|
||||||
|
*
|
||||||
|
* @param fieldName must not be {@literal null}.
|
||||||
|
* @return new instance of {@link Bottom}.
|
||||||
|
*/
|
||||||
|
public First input(String fieldName) {
|
||||||
|
return new First(append("input", Fields.field(fieldName)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the expression building the value to serve as source.
|
||||||
|
*
|
||||||
|
* @param expression must not be {@literal null}.
|
||||||
|
* @return new instance of {@link Bottom}.
|
||||||
|
*/
|
||||||
|
public First input(AggregationExpression expression) {
|
||||||
|
return new First(append("input", expression));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getMongoMethod() {
|
||||||
|
return "$firstN";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,6 +216,8 @@ public class MethodReferenceNode extends ExpressionNode {
|
|||||||
.mappingParametersTo("output", "sortBy"));
|
.mappingParametersTo("output", "sortBy"));
|
||||||
map.put("bottomN", mapArgRef().forOperator("$bottomN") //
|
map.put("bottomN", mapArgRef().forOperator("$bottomN") //
|
||||||
.mappingParametersTo("n", "output", "sortBy"));
|
.mappingParametersTo("n", "output", "sortBy"));
|
||||||
|
map.put("firstN", mapArgRef().forOperator("$firstN") //
|
||||||
|
.mappingParametersTo("n", "input"));
|
||||||
|
|
||||||
// CONVERT OPERATORS
|
// CONVERT OPERATORS
|
||||||
map.put("convert", mapArgRef().forOperator("$convert") //
|
map.put("convert", mapArgRef().forOperator("$convert") //
|
||||||
@@ -230,7 +232,6 @@ public class MethodReferenceNode extends ExpressionNode {
|
|||||||
map.put("toString", singleArgRef().forOperator("$toString"));
|
map.put("toString", singleArgRef().forOperator("$toString"));
|
||||||
map.put("degreesToRadians", singleArgRef().forOperator("$degreesToRadians"));
|
map.put("degreesToRadians", singleArgRef().forOperator("$degreesToRadians"));
|
||||||
|
|
||||||
|
|
||||||
FUNCTIONS = Collections.unmodifiableMap(map);
|
FUNCTIONS = Collections.unmodifiableMap(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,6 +89,27 @@ class SelectionOperatorUnitTests {
|
|||||||
"""));
|
"""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // GH-4139
|
||||||
|
void firstNMapsFieldNamesCorrectly() {
|
||||||
|
|
||||||
|
MongoMappingContext mappingContext = new MongoMappingContext();
|
||||||
|
RelaxedTypeBasedAggregationOperationContext aggregationContext = new RelaxedTypeBasedAggregationOperationContext(
|
||||||
|
Player.class, mappingContext,
|
||||||
|
new QueryMapper(new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, mappingContext)));
|
||||||
|
|
||||||
|
Document document = SelectionOperators.First.first(3).of("score").toDocument(aggregationContext);
|
||||||
|
|
||||||
|
assertThat(document).isEqualTo(Document.parse("""
|
||||||
|
{
|
||||||
|
$firstN:
|
||||||
|
{
|
||||||
|
n: 3,
|
||||||
|
input: "$s_cor_e"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""));
|
||||||
|
}
|
||||||
|
|
||||||
static class Player {
|
static class Player {
|
||||||
|
|
||||||
@Field("player_id") String playerId;
|
@Field("player_id") String playerId;
|
||||||
|
|||||||
@@ -1184,6 +1184,11 @@ public class SpelExpressionTransformerUnitTests {
|
|||||||
assertThat(transform("bottomN(3, new String[]{\"$playerId\", \"$score\" }, { \"score\" : -1 })")).isEqualTo("{ $bottomN : { n : 3, output: [ \"$playerId\", \"$score\" ], sortBy: { \"score\": -1 }}}");
|
assertThat(transform("bottomN(3, new String[]{\"$playerId\", \"$score\" }, { \"score\" : -1 })")).isEqualTo("{ $bottomN : { n : 3, output: [ \"$playerId\", \"$score\" ], sortBy: { \"score\": -1 }}}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // GH-4139
|
||||||
|
void shouldRenderFirstN() {
|
||||||
|
assertThat(transform("firstN(3, \"$score\")")).isEqualTo("{ $firstN : { n : 3, input : \"$score\" }}");
|
||||||
|
}
|
||||||
|
|
||||||
private Document transform(String expression, Object... params) {
|
private Document transform(String expression, Object... params) {
|
||||||
return (Document) transformer.transform(expression, Aggregation.DEFAULT_CONTEXT, params);
|
return (Document) transformer.transform(expression, Aggregation.DEFAULT_CONTEXT, params);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user