Support aggregation operators $first and $last via expression method reference.

This commit registers the first(...) and last(...) methods for transformation via SpEL.
Also update reference and java documentation and add issue reference to tests.

Original Pull Request: #3866
This commit is contained in:
Christoph Strobl
2022-01-24 09:22:10 +01:00
parent a2243536b2
commit bcbefa9264
5 changed files with 34 additions and 16 deletions

View File

@@ -35,6 +35,7 @@ import org.springframework.util.Assert;
* @author Christoph Strobl
* @author Mark Paluch
* @author Shashank Sharma
* @author Divya Srivastava
* @since 1.0
*/
public class ArrayOperators {
@@ -364,10 +365,11 @@ public class ArrayOperators {
}
/**
* Creates new {@link AggregationExpression} that return the first element in the given array.
* Creates new {@link AggregationExpression} that return the first element in the associated array.
* <strong>NOTE:</strong> Requires MongoDB 4.4 or later.
*
* @return new instance of {@link First}.
* @since 3.4
*/
public First first() {
@@ -382,7 +384,8 @@ public class ArrayOperators {
* Creates new {@link AggregationExpression} that return the last element in the given array.
* <strong>NOTE:</strong> Requires MongoDB 4.4 or later.
*
* @return new instance of {@link First}.
* @return new instance of {@link Last}.
* @since 3.4
*/
public Last last() {
@@ -1847,6 +1850,9 @@ public class ArrayOperators {
* {@link AggregationExpression} for {@code $first} that returns the first element in an array. <br />
* <strong>NOTE:</strong> Requires MongoDB 4.4 or later.
*
* @author Divya Srivastava
* @author Christoph Strobl
* @since 3.4
*/
public static class First extends AbstractAggregationExpression {
@@ -1875,7 +1881,7 @@ public class ArrayOperators {
}
/**
* Returns the first element of the array of the given {@link AggregationExpression expression}.
* Returns the first element of the array computed by the given {@link AggregationExpression expression}.
*
* @param expression must not be {@literal null}.
* @return new instance of {@link First}.
@@ -1898,6 +1904,9 @@ public class ArrayOperators {
* {@link AggregationExpression} for {@code $last} that returns the last element in an array. <br />
* <strong>NOTE:</strong> Requires MongoDB 4.4 or later.
*
* @author Divya Srivastava
* @author Christoph Strobl
* @since 3.4
*/
public static class Last extends AbstractAggregationExpression {
@@ -1906,7 +1915,7 @@ public class ArrayOperators {
}
/**
* Returns the first element in the given array.
* Returns the last element in the given array.
*
* @param array must not be {@literal null}.
* @return new instance of {@link Last}.
@@ -1926,7 +1935,7 @@ public class ArrayOperators {
}
/**
* Returns the last element of the array of the given {@link AggregationExpression expression}.
* Returns the last element of the array computed buy the given {@link AggregationExpression expression}.
*
* @param expression must not be {@literal null}.
* @return new instance of {@link Last}.
@@ -1944,5 +1953,4 @@ public class ArrayOperators {
return "$last";
}
}
}

View File

@@ -137,7 +137,9 @@ public class MethodReferenceNode extends ExpressionNode {
map.put("concatArrays", arrayArgRef().forOperator("$concatArrays"));
map.put("filter", mapArgRef().forOperator("$filter") //
.mappingParametersTo("input", "as", "cond"));
map.put("first", singleArgRef().forOperator("$first"));
map.put("isArray", singleArgRef().forOperator("$isArray"));
map.put("last", singleArgRef().forOperator("$last"));
map.put("size", singleArgRef().forOperator("$size"));
map.put("slice", arrayArgRef().forOperator("$slice"));
map.put("reverseArray", singleArgRef().forOperator("$reverseArray"));

View File

@@ -23,7 +23,6 @@ import java.util.List;
import org.bson.Document;
import org.junit.jupiter.api.Test;
import org.springframework.data.mongodb.core.aggregation.ArrayOperators.ArrayToObject;
/**
@@ -31,6 +30,7 @@ import org.springframework.data.mongodb.core.aggregation.ArrayOperators.ArrayToO
*
* @author Christoph Strobl
* @author Shashank Sharma
* @author Divya Srivastava
* @currentRead Royal Assassin - Robin Hobb
*/
public class ArrayOperatorsUnitTests {
@@ -130,46 +130,45 @@ public class ArrayOperatorsUnitTests {
.isEqualTo("{ \"$in\" : [\"$userName\", " + VALUE_LIST_STRING + "] }");
}
@Test
@Test // GH-3694
public void firstWithValueList() {
assertThat(ArrayOperators.arrayOf(VALUE_LIST).first().toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo("{ \"$first\" : " + VALUE_LIST_STRING + "}");
}
@Test
@Test // GH-3694
public void firstWithExpression() {
assertThat(ArrayOperators.arrayOf(EXPRESSION).first().toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo("{ \"$first\" : " + EXPRESSION_STRING + "}");
}
@Test
@Test // GH-3694
public void firstWithFieldReference() {
assertThat(ArrayOperators.arrayOf("field").first().toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo("{ $first : \"$field\" }");
}
@Test
@Test // GH-3694
public void lastWithValueList() {
assertThat(ArrayOperators.arrayOf(VALUE_LIST).last().toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo("{ \"$last\" : " + VALUE_LIST_STRING + "}");
}
@Test
@Test // GH-3694
public void lastWithExpression() {
assertThat(ArrayOperators.arrayOf(EXPRESSION).last().toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo("{ \"$last\" : " + EXPRESSION_STRING + "}");
}
@Test
@Test // GH-3694
public void lastWithFieldReference() {
assertThat(ArrayOperators.arrayOf("field").last().toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo("{ $last : \"$field\" }");
}
}

View File

@@ -411,6 +411,16 @@ public class SpelExpressionTransformerUnitTests {
assertThat(transform("arrayElemAt(a, 10)")).isEqualTo("{ \"$arrayElemAt\" : [ \"$a\" , 10]}");
}
@Test // GH-3694
void shouldRenderMethodReferenceNodeFirst() {
assertThat(transform("first(a)")).isEqualTo("{ \"$first\" : \"$a\" }");
}
@Test // GH-3694
void shouldRenderMethodReferenceNodeLast() {
assertThat(transform("last(a)")).isEqualTo("{ \"$last\" : \"$a\" }");
}
@Test // DATAMONGO-1530
void shouldRenderMethodReferenceNodeConcatArrays() {
assertThat(transform("concatArrays(a, b, c)"))
@@ -879,7 +889,6 @@ public class SpelExpressionTransformerUnitTests {
.isEqualTo("{ \"$replaceAll\" : {\"input\" : \"$field\" , \"find\" : \"bar\" , \"replacement\" : \"baz\"}}");
}
@Test // DATAMONGO-2077
void shouldRenderConvertWithoutOptionalParameters() {

View File

@@ -94,7 +94,7 @@ At the time of this writing, we provide support for the following Aggregation Op
| `eq` (+++*+++ via `is`), `gt`, `gte`, `lt`, `lte`, `ne`
| Array Aggregation Operators
| `arrayElementAt`, `arrayToObject`, `concatArrays`, `filter`, `in`, `indexOfArray`, `isArray`, `range`, `reverseArray`, `reduce`, `size`, `slice`, `zip`
| `arrayElementAt`, `arrayToObject`, `concatArrays`, `filter`, `first`, `in`, `indexOfArray`, `isArray`, `last`, range`, `reverseArray`, `reduce`, `size`, `slice`, `zip`
| Literal Operators
| `literal`