DATAMONGO-2320 - Fix aggregation field reference for $filter operator.
We now render field and local variable references correctly when using the $filter aggregation operator. Prior to this commit field references had been rendered with an additional $ prefix. Original pull request: #776.
This commit is contained in:
committed by
Mark Paluch
parent
74325d5193
commit
370db2dce5
@@ -496,7 +496,7 @@ public class ArrayOperators {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NestedDelegatingExpressionAggregationOperationContext nea = new NestedDelegatingExpressionAggregationOperationContext(
|
NestedDelegatingExpressionAggregationOperationContext nea = new NestedDelegatingExpressionAggregationOperationContext(
|
||||||
context);
|
context, Collections.singleton(as));
|
||||||
return ((AggregationExpression) condition).toDocument(nea);
|
return ((AggregationExpression) condition).toDocument(nea);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core.aggregation;
|
package org.springframework.data.mongodb.core.aggregation;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
|
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
|
||||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExpressionFieldReference;
|
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExpressionFieldReference;
|
||||||
@@ -31,16 +36,18 @@ import org.springframework.util.Assert;
|
|||||||
class NestedDelegatingExpressionAggregationOperationContext implements AggregationOperationContext {
|
class NestedDelegatingExpressionAggregationOperationContext implements AggregationOperationContext {
|
||||||
|
|
||||||
private final AggregationOperationContext delegate;
|
private final AggregationOperationContext delegate;
|
||||||
|
private final Set<String> inners;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new {@link NestedDelegatingExpressionAggregationOperationContext}.
|
* Creates new {@link NestedDelegatingExpressionAggregationOperationContext}.
|
||||||
*
|
*
|
||||||
* @param referenceContext must not be {@literal null}.
|
* @param referenceContext must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
public NestedDelegatingExpressionAggregationOperationContext(AggregationOperationContext referenceContext) {
|
NestedDelegatingExpressionAggregationOperationContext(AggregationOperationContext referenceContext, Collection<Field> inners) {
|
||||||
|
|
||||||
Assert.notNull(referenceContext, "Reference context must not be null!");
|
Assert.notNull(referenceContext, "Reference context must not be null!");
|
||||||
this.delegate = referenceContext;
|
this.delegate = referenceContext;
|
||||||
|
this.inners = inners.stream().map(Field::getName).collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -58,7 +65,22 @@ class NestedDelegatingExpressionAggregationOperationContext implements Aggregati
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public FieldReference getReference(Field field) {
|
public FieldReference getReference(Field field) {
|
||||||
return new ExpressionFieldReference(delegate.getReference(field));
|
|
||||||
|
FieldReference reference = delegate.getReference(field);
|
||||||
|
return !isInnerVariableReference(field) ? reference : new ExpressionFieldReference(delegate.getReference(field)) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isInnerVariableReference(Field field) {
|
||||||
|
|
||||||
|
if(inners.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(inners.contains(field.getName())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return inners.stream().anyMatch(it -> field.getTarget().contains(".") && field.getTarget().startsWith(it));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ package org.springframework.data.mongodb.core.aggregation;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
import org.springframework.data.mongodb.core.aggregation.VariableOperators.Let.ExpressionVariable;
|
import org.springframework.data.mongodb.core.aggregation.VariableOperators.Let.ExpressionVariable;
|
||||||
@@ -185,7 +187,8 @@ public class VariableOperators {
|
|||||||
map.putAll(context.getMappedObject(input));
|
map.putAll(context.getMappedObject(input));
|
||||||
map.put("as", itemVariableName);
|
map.put("as", itemVariableName);
|
||||||
map.put("in",
|
map.put("in",
|
||||||
functionToApply.toDocument(new NestedDelegatingExpressionAggregationOperationContext(operationContext)));
|
functionToApply.toDocument(new NestedDelegatingExpressionAggregationOperationContext(operationContext,
|
||||||
|
Collections.singleton(Fields.field(itemVariableName)))));
|
||||||
|
|
||||||
return new Document("$map", map);
|
return new Document("$map", map);
|
||||||
}
|
}
|
||||||
@@ -322,12 +325,14 @@ public class VariableOperators {
|
|||||||
|
|
||||||
private Document getMappedVariable(ExpressionVariable var, AggregationOperationContext context) {
|
private Document getMappedVariable(ExpressionVariable var, AggregationOperationContext context) {
|
||||||
|
|
||||||
return new Document(var.variableName, var.expression instanceof AggregationExpression
|
return new Document(var.variableName,
|
||||||
? ((AggregationExpression) var.expression).toDocument(context) : var.expression);
|
var.expression instanceof AggregationExpression ? ((AggregationExpression) var.expression).toDocument(context)
|
||||||
|
: var.expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object getMappedIn(AggregationOperationContext context) {
|
private Object getMappedIn(AggregationOperationContext context) {
|
||||||
return expression.toDocument(new NestedDelegatingExpressionAggregationOperationContext(context));
|
return expression.toDocument(new NestedDelegatingExpressionAggregationOperationContext(context,
|
||||||
|
this.vars.stream().map(var -> Fields.field(var.variableName)).collect(Collectors.toList())));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -123,6 +123,29 @@ public class FilterExpressionUnitTests {
|
|||||||
assertThat($filter, is(expected));
|
assertThat($filter, is(expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // DATAMONGO-2320
|
||||||
|
public void shouldConstructFilterExpressionCorrectlyWhenConditionContainsFieldReference() {
|
||||||
|
|
||||||
|
Aggregation agg = Aggregation.newAggregation(Aggregation.project().and((ctx) -> new Document()).as("field-1")
|
||||||
|
.and(filter("items").as("item").by(ComparisonOperators.valueOf("item.price").greaterThan("field-1")))
|
||||||
|
.as("items"));
|
||||||
|
|
||||||
|
Document dbo = agg.toDocument("sales", Aggregation.DEFAULT_CONTEXT);
|
||||||
|
|
||||||
|
List<Object> pipeline = DocumentTestUtils.getAsDBList(dbo, "pipeline");
|
||||||
|
Document $project = DocumentTestUtils.getAsDocument((Document) pipeline.get(0), "$project");
|
||||||
|
Document items = DocumentTestUtils.getAsDocument($project, "items");
|
||||||
|
Document $filter = DocumentTestUtils.getAsDocument(items, "$filter");
|
||||||
|
|
||||||
|
Document expected = Document.parse("{" + //
|
||||||
|
"input: \"$items\"," + //
|
||||||
|
"as: \"item\"," + //
|
||||||
|
"cond: { $gt: [ \"$$item.price\", \"$field-1\" ] }" + //
|
||||||
|
"}");
|
||||||
|
|
||||||
|
assertThat($filter).isEqualTo(new Document(expected));
|
||||||
|
}
|
||||||
|
|
||||||
static class Sales {
|
static class Sales {
|
||||||
|
|
||||||
List<Object> items;
|
List<Object> items;
|
||||||
|
|||||||
Reference in New Issue
Block a user