Browse Source

Accept expression as input for filter aggregation operator.

Closes #4394
Original pull request: #4395
pull/4427/head
Christoph Strobl 3 years ago committed by Mark Paluch
parent
commit
048af85be0
No known key found for this signature in database
GPG Key ID: 4406B84C1661DCD1
  1. 62
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArrayOperators.java
  2. 17
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/FilterExpressionUnitTests.java

62
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArrayOperators.java

@ -79,7 +79,7 @@ public class ArrayOperators {
private final @Nullable String fieldReference; private final @Nullable String fieldReference;
private final @Nullable AggregationExpression expression; private final @Nullable AggregationExpression expression;
private final @Nullable Collection values; private final @Nullable Collection<?> values;
/** /**
* Creates new {@link ArrayOperatorFactory} for given {@literal fieldReference}. * Creates new {@link ArrayOperatorFactory} for given {@literal fieldReference}.
@ -214,6 +214,10 @@ public class ArrayOperators {
return Filter.filter(fieldReference); return Filter.filter(fieldReference);
} }
if (usesExpression()) {
return Filter.filter(expression);
}
Assert.state(values != null, "Values must not be null"); Assert.state(values != null, "Values must not be null");
return Filter.filter(new ArrayList<>(values)); return Filter.filter(new ArrayList<>(values));
} }
@ -317,7 +321,8 @@ public class ArrayOperators {
} }
/** /**
* Creates new {@link AggregationExpression} that takes the associated array and sorts it by the given {@link Sort order}. * Creates new {@link AggregationExpression} that takes the associated array and sorts it by the given {@link Sort
* order}.
* *
* @return new instance of {@link SortArray}. * @return new instance of {@link SortArray}.
* @since 4.0 * @since 4.0
@ -397,8 +402,8 @@ public class ArrayOperators {
} }
/** /**
* Creates new {@link AggregationExpression} that return the last element in the given array. * Creates new {@link AggregationExpression} that return the last element in the given array. <strong>NOTE:</strong>
* <strong>NOTE:</strong> Requires MongoDB 4.4 or later. * Requires MongoDB 4.4 or later.
* *
* @return new instance of {@link Last}. * @return new instance of {@link Last}.
* @since 3.4 * @since 3.4
@ -649,6 +654,19 @@ public class ArrayOperators {
return new FilterExpressionBuilder().filter(field); return new FilterExpressionBuilder().filter(field);
} }
/**
* Set the {@link AggregationExpression} resolving to an arry to apply the {@code $filter} to.
*
* @param expression must not be {@literal null}.
* @return never {@literal null}.
* @since 4.2
*/
public static AsBuilder filter(AggregationExpression expression) {
Assert.notNull(expression, "Field must not be null");
return new FilterExpressionBuilder().filter(expression);
}
/** /**
* Set the {@literal values} to apply the {@code $filter} to. * Set the {@literal values} to apply the {@code $filter} to.
* *
@ -681,7 +699,16 @@ public class ArrayOperators {
} }
private Object getMappedInput(AggregationOperationContext context) { private Object getMappedInput(AggregationOperationContext context) {
return input instanceof Field field ? context.getReference(field).toString() : input;
if (input instanceof Field field) {
return context.getReference(field).toString();
}
if (input instanceof AggregationExpression expression) {
return expression.toDocument(context);
}
return input;
} }
private Object getMappedCondition(AggregationOperationContext context) { private Object getMappedCondition(AggregationOperationContext context) {
@ -715,6 +742,15 @@ public class ArrayOperators {
* @return * @return
*/ */
AsBuilder filter(Field field); AsBuilder filter(Field field);
/**
* Set the {@link AggregationExpression} resolving to an array to apply the {@code $filter} to.
*
* @param expression must not be {@literal null}.
* @return
* @since 4.1.1
*/
AsBuilder filter(AggregationExpression expression);
} }
/** /**
@ -797,6 +833,14 @@ public class ArrayOperators {
return this; return this;
} }
@Override
public AsBuilder filter(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null");
filter.input = expression;
return this;
}
@Override @Override
public ConditionBuilder as(String variableName) { public ConditionBuilder as(String variableName) {
@ -1333,7 +1377,7 @@ public class ArrayOperators {
Assert.notNull(expressions, "PropertyExpressions must not be null"); Assert.notNull(expressions, "PropertyExpressions must not be null");
return new Reduce(Fields.field(fieldReference), initialValue, return new Reduce(Fields.field(fieldReference), initialValue,
Arrays.<AggregationExpression>asList(expressions)); Arrays.<AggregationExpression> asList(expressions));
} }
}; };
} }
@ -1690,7 +1734,7 @@ public class ArrayOperators {
* @author Christoph Strobl * @author Christoph Strobl
* @author Shashank Sharma * @author Shashank Sharma
* @see <a href= * @see <a href=
* "https://docs.mongodb.com/manual/reference/operator/aggregation/in/">https://docs.mongodb.com/manual/reference/operator/aggregation/in/</a> * "https://docs.mongodb.com/manual/reference/operator/aggregation/in/">https://docs.mongodb.com/manual/reference/operator/aggregation/in/</a>
* @since 2.2 * @since 2.2
*/ */
public static class In extends AbstractAggregationExpression { public static class In extends AbstractAggregationExpression {
@ -1779,7 +1823,7 @@ public class ArrayOperators {
* *
* @author Christoph Strobl * @author Christoph Strobl
* @see <a href= * @see <a href=
* "https://docs.mongodb.com/manual/reference/operator/aggregation/arrayToObject/">https://docs.mongodb.com/manual/reference/operator/aggregation/arrayToObject/</a> * "https://docs.mongodb.com/manual/reference/operator/aggregation/arrayToObject/">https://docs.mongodb.com/manual/reference/operator/aggregation/arrayToObject/</a>
* @since 2.1 * @since 2.1
*/ */
public static class ArrayToObject extends AbstractAggregationExpression { public static class ArrayToObject extends AbstractAggregationExpression {
@ -1976,7 +2020,7 @@ public class ArrayOperators {
/** /**
* Set the order to put elements in. * Set the order to put elements in.
* *
* @param sort must not be {@literal null}. * @param sort must not be {@literal null}.
* @return new instance of {@link SortArray}. * @return new instance of {@link SortArray}.
*/ */

17
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/FilterExpressionUnitTests.java

@ -117,6 +117,23 @@ class FilterExpressionUnitTests {
assertThat($filter).isEqualTo(new Document(expected)); assertThat($filter).isEqualTo(new Document(expected));
} }
@Test // GH-4394
void filterShouldAcceptExpression() {
Document $filter = ArrayOperators.arrayOf(ObjectOperators.valueOf("data.metadata").toArray()).filter().as("item")
.by(ComparisonOperators.valueOf("item.price").greaterThan("field-1")).toDocument(Aggregation.DEFAULT_CONTEXT);
Document expected = Document.parse("""
{ $filter : {
input: { $objectToArray: "$data.metadata" },
as: "item",
cond: { $gt: [ "$$item.price", "$field-1" ] }
}}
""");
assertThat($filter).isEqualTo(expected);
}
private Document extractFilterOperatorFromDocument(Document source) { private Document extractFilterOperatorFromDocument(Document source) {
List<Object> pipeline = DocumentTestUtils.getAsDBList(source, "pipeline"); List<Object> pipeline = DocumentTestUtils.getAsDBList(source, "pipeline");

Loading…
Cancel
Save