From 899b43a29bf40b76d43ef888f6630622a77c82b2 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Mon, 23 Sep 2019 10:03:23 +0200 Subject: [PATCH] DATAMONGO-2377 - Fix handling of $$value and $$this in field exposing aggregation. Internal field references to $$this and $$value are now no longer mapped against exposed fields which had caused errors before. Original pull request: #792. --- ...osedFieldsAggregationOperationContext.java | 5 +++++ .../data/mongodb/core/aggregation/Field.java | 8 ++++++++ .../data/mongodb/core/aggregation/Fields.java | 5 +++++ .../aggregation/AggregationUnitTests.java | 19 +++++++++++++++++++ 4 files changed, 37 insertions(+) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ExposedFieldsAggregationOperationContext.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ExposedFieldsAggregationOperationContext.java index 7c5778eac..c9b56eba1 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ExposedFieldsAggregationOperationContext.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ExposedFieldsAggregationOperationContext.java @@ -69,6 +69,11 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo */ @Override public FieldReference getReference(Field field) { + + if(field.isInternal()) { + return new DirectFieldReference(new ExposedField(field, true)); + } + return getReference(field, field.getTarget()); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/Field.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/Field.java index 6e314d8d8..16aff3cec 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/Field.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/Field.java @@ -43,4 +43,12 @@ public interface Field { * @return */ boolean isAliased(); + + /** + * @return true if the field name references a local value such as {@code $$this}. + * @since 2.1.11 + */ + default boolean isInternal() { + return false; + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/Fields.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/Fields.java index 664c5c370..0780f84d5 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/Fields.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/Fields.java @@ -283,6 +283,11 @@ public final class Fields implements Iterable { return !getName().equals(getTarget()); } + @Override + public boolean isInternal() { + return getRaw().endsWith("$$this") || getRaw().endsWith("$$value"); + } + /** * @return {@literal true} in case the field name starts with {@code $$}. * @since 1.10 diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationUnitTests.java index 0a2b93777..48acc3e2a 100755 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationUnitTests.java @@ -22,6 +22,7 @@ import static org.springframework.data.mongodb.test.util.Assertions.*; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.bson.Document; @@ -569,6 +570,24 @@ public class AggregationUnitTests { assertThat($project.containsKey("plts.ests")).isTrue(); } + @Test // DATAMONGO-2377 + public void shouldAllowInternal$$thisAnd$$valueReferences() { + + Document untyped = newAggregation( // + Arrays.asList( // + (group("uid", "data.sourceId") // + .push("data.attributeRecords").as("attributeRecordArrays")), // + (project() // + .and(ArrayOperators.arrayOf("attributeRecordArrays") // + .reduce(ArrayOperators.arrayOf("$$value").concat("$$this")) // + .startingWith(Collections.emptyList())) // + .as("attributeRecordArrays")) // + )).toDocument("collection-1", DEFAULT_CONTEXT); + + assertThat(extractPipelineElement(untyped, 1, "$project")).isEqualTo(Document.parse( + "{\"attributeRecordArrays\": {\"$reduce\": {\"input\": \"$attributeRecordArrays\", \"initialValue\": [], \"in\": {\"$concatArrays\": [\"$$value\", \"$$this\"]}}}}")); + } + private Document extractPipelineElement(Document agg, int index, String operation) { List pipeline = (List) agg.get("pipeline");