diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArrayOperators.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArrayOperators.java
index a5b0913c3..23ed32ec6 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArrayOperators.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArrayOperators.java
@@ -78,7 +78,7 @@ public class ArrayOperators {
private final @Nullable String fieldReference;
private final @Nullable AggregationExpression expression;
- private final @Nullable Collection values;
+ private final @Nullable Collection> values;
/**
* Creates new {@link ArrayOperatorFactory} for given {@literal fieldReference}.
@@ -213,6 +213,10 @@ public class ArrayOperators {
return Filter.filter(fieldReference);
}
+ if (usesExpression()) {
+ return Filter.filter(expression);
+ }
+
Assert.state(values != null, "Values must not be null!");
return Filter.filter(new ArrayList<>(values));
}
@@ -363,7 +367,7 @@ public class ArrayOperators {
return usesExpression() ? ArrayToObject.arrayValueOfToObject(expression) : ArrayToObject.arrayToObject(values);
}
-
+
/**
* Creates new {@link AggregationExpression} that return the first element in the associated array.
* NOTE: Requires MongoDB 4.4 or later.
@@ -379,10 +383,10 @@ public class ArrayOperators {
return usesExpression() ? First.firstOf(expression) : First.first(values);
}
-
+
/**
- * Creates new {@link AggregationExpression} that return the last element in the given array.
- * NOTE: Requires MongoDB 4.4 or later.
+ * Creates new {@link AggregationExpression} that return the last element in the given array. NOTE:
+ * Requires MongoDB 4.4 or later.
*
* @return new instance of {@link Last}.
* @since 3.4
@@ -633,6 +637,19 @@ public class ArrayOperators {
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.
*
@@ -669,7 +686,16 @@ public class ArrayOperators {
}
private Object getMappedInput(AggregationOperationContext context) {
- return input instanceof Field ? context.getReference((Field) input).toString() : input;
+
+ if (input instanceof Field) {
+ return context.getReference((Field) input).toString();
+ }
+
+ if (input instanceof AggregationExpression) {
+ return ((AggregationExpression) input).toDocument(context);
+ }
+
+ return input;
}
private Object getMappedCondition(AggregationOperationContext context) {
@@ -703,6 +729,15 @@ public class ArrayOperators {
* @return
*/
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 3.4.13
+ */
+ AsBuilder filter(AggregationExpression expression);
}
/**
@@ -793,6 +828,14 @@ public class ArrayOperators {
return this;
}
+ @Override
+ public AsBuilder filter(AggregationExpression expression) {
+
+ Assert.notNull(expression, "Expression must not be null");
+ filter.input = expression;
+ return this;
+ }
+
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.ArrayOperators.Filter.AsBuilder#as(java.lang.String)
@@ -1348,7 +1391,7 @@ public class ArrayOperators {
Assert.notNull(expressions, "PropertyExpressions must not be null");
return new Reduce(Fields.field(fieldReference), initialValue,
- Arrays.asList(expressions));
+ Arrays. asList(expressions));
}
};
}
@@ -1708,7 +1751,7 @@ public class ArrayOperators {
* @author Christoph Strobl
* @author Shashank Sharma
* @see https://docs.mongodb.com/manual/reference/operator/aggregation/in/
+ * "https://docs.mongodb.com/manual/reference/operator/aggregation/in/">https://docs.mongodb.com/manual/reference/operator/aggregation/in/
* @since 2.2
*/
public static class In extends AbstractAggregationExpression {
@@ -1797,7 +1840,7 @@ public class ArrayOperators {
*
* @author Christoph Strobl
* @see https://docs.mongodb.com/manual/reference/operator/aggregation/arrayToObject/
+ * "https://docs.mongodb.com/manual/reference/operator/aggregation/arrayToObject/">https://docs.mongodb.com/manual/reference/operator/aggregation/arrayToObject/
* @since 2.1
*/
public static class ArrayToObject extends AbstractAggregationExpression {
@@ -1845,7 +1888,7 @@ public class ArrayOperators {
return "$arrayToObject";
}
}
-
+
/**
* {@link AggregationExpression} for {@code $first} that returns the first element in an array.
* NOTE: Requires MongoDB 4.4 or later.
@@ -1899,7 +1942,7 @@ public class ArrayOperators {
return "$first";
}
}
-
+
/**
* {@link AggregationExpression} for {@code $last} that returns the last element in an array.
* NOTE: Requires MongoDB 4.4 or later.
diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/FilterExpressionUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/FilterExpressionUnitTests.java
index 4cee9bcdb..a4b8d9da8 100644
--- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/FilterExpressionUnitTests.java
+++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/FilterExpressionUnitTests.java
@@ -25,12 +25,8 @@ import org.bson.Document;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
-
-import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.DocumentTestUtils;
-import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver;
import org.springframework.data.mongodb.core.convert.QueryMapper;
@@ -121,6 +117,21 @@ class FilterExpressionUnitTests {
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) {
List