From aecca2998bcbf0655abfefa782dd480326040813 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Fri, 10 Mar 2023 12:25:30 +0100 Subject: [PATCH] Fix field resolution for `ExposedFieldsAggregationContext`. This commit fixes an issue where the context is not relaxed and errors on unknown fields if multiple stages of nesting contexts happen. Closes #3917 Original pull request: #4328 --- ...osedFieldsAggregationOperationContext.java | 19 +++++++++++++++ .../aggregation/AggregationUnitTests.java | 23 +++++++++++++++++++ 2 files changed, 42 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 6572eabcf..1a88175d7 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 @@ -96,6 +96,25 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo return exposedField; } + if(rootContext instanceof RelaxedTypeBasedAggregationOperationContext) { + return new DirectFieldReference(new ExposedField(new Field() { + @Override + public String getName() { + return name; + } + + @Override + public String getTarget() { + return field != null ? field.getTarget() : name; + } + + @Override + public boolean isAliased() { + return true; + } + }, true)); + } + throw new IllegalArgumentException(String.format("Invalid reference '%s'", name)); } 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 9670bcf03..64bd9a141 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 @@ -29,6 +29,7 @@ import java.util.Map; import org.bson.Document; import org.junit.jupiter.api.Test; import org.springframework.data.annotation.Id; +import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond; import org.springframework.data.mongodb.core.aggregation.ProjectionOperationUnitTests.BookWithFieldAnnotation; @@ -629,6 +630,28 @@ public class AggregationUnitTests { Document target = newAggregation(stage).toDocument("col-1", DEFAULT_CONTEXT); assertThat(extractPipelineElement(target, 0, "$project")).containsKey("name"); } + + @Test // GH-3917 + void inheritedFieldsExposingContextShouldNotFailOnUnknownFieldReferenceForRelaxedRootContext() { + + List aggregationOperations = new ArrayList<>(); + + GroupOperation groupOperation = Aggregation.group("_id", "label_name"); + aggregationOperations.add(groupOperation); + + ProjectionOperation projectionOperation = Aggregation.project("label_name").andExclude("_id"); + aggregationOperations.add(projectionOperation); + + Sort sort = Sort.by(Sort.Direction.DESC, "serial_number"); + SortOperation sortOperation = new SortOperation(sort).and(Sort.Direction.DESC, "label_name"); + aggregationOperations.add(sortOperation); + + MongoMappingContext mappingContext = new MongoMappingContext(); + QueryMapper queryMapper = new QueryMapper(new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, mappingContext)); + + List documents = newAggregation(City.class, aggregationOperations).toPipeline(new RelaxedTypeBasedAggregationOperationContext(City.class, mappingContext, queryMapper)); + assertThat(documents.get(2)).isEqualTo("{ $sort : { 'serial_number' : -1, 'label_name' : -1 } }"); + } private Document extractPipelineElement(Document agg, int index, String operation) {