Skip to content

Commit e71ec87

Browse files
divyajnu08mp911de
authored andcommitted
Add support for $expr operator.
Also, allow construction of $match with an AggregationExpression. Closes #3790
1 parent f24e8e5 commit e71ec87

File tree

8 files changed

+187
-3
lines changed

8 files changed

+187
-3
lines changed

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

+1
Original file line numberDiff line numberDiff line change
@@ -201,4 +201,5 @@ public interface ValueAppender {
201201
AddFieldsOperationBuilder withValueOfExpression(String operation, Object... values);
202202
}
203203
}
204+
204205
}

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

+11-1
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,17 @@ public static MatchOperation match(Criteria criteria) {
498498
public static MatchOperation match(CriteriaDefinition criteria) {
499499
return new MatchOperation(criteria);
500500
}
501-
501+
502+
/**
503+
* Creates a new {@link MatchOperation}
504+
*
505+
* @return new instance of {@link MatchOperation}.
506+
* @since 1.10
507+
*/
508+
public static MatchOperation match() {
509+
return new MatchOperation();
510+
}
511+
502512
/**
503513
* Creates a new {@link GeoNearOperation} instance from the given {@link NearQuery} and the {@code distanceField}. The
504514
* {@code distanceField} defines output field that contains the calculated distance.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package org.springframework.data.mongodb.core.aggregation;
2+
3+
import org.springframework.util.Assert;
4+
5+
public class EvaluationOperators {
6+
7+
/**
8+
* Take the value resulting from the given fieldReference.
9+
*
10+
* @param fieldReference must not be {@literal null}.
11+
* @return new instance of {@link EvaluationOperatorFactory}.
12+
*/
13+
public static EvaluationOperatorFactory valueOf(String fieldReference) {
14+
return new EvaluationOperatorFactory(fieldReference);
15+
}
16+
17+
/**
18+
* Take the value resulting from the given {@link AggregationExpression}.
19+
*
20+
* @param expression must not be {@literal null}.
21+
* @return new instance of {@link EvaluationOperatorFactory}.
22+
*/
23+
public static EvaluationOperatorFactory valueOf(AggregationExpression expression) {
24+
return new EvaluationOperatorFactory(expression);
25+
}
26+
27+
public static class EvaluationOperatorFactory {
28+
29+
private final String fieldReference;
30+
private final AggregationExpression expression;
31+
32+
/**
33+
* Creates new {@link EvaluationOperatorFactory} for given {@literal fieldReference}.
34+
*
35+
* @param fieldReference must not be {@literal null}.
36+
*/
37+
public EvaluationOperatorFactory(String fieldReference) {
38+
39+
Assert.notNull(fieldReference, "FieldReference must not be null!");
40+
this.fieldReference = fieldReference;
41+
this.expression = null;
42+
}
43+
44+
45+
/**
46+
* Creates new {@link EvaluationOperatorFactory} for given {@link AggregationExpression}.
47+
*
48+
* @param expression must not be {@literal null}.
49+
*/
50+
public EvaluationOperatorFactory(AggregationExpression expression) {
51+
52+
Assert.notNull(expression, "Expression must not be null!");
53+
this.fieldReference = null;
54+
this.expression = expression;
55+
}
56+
57+
/**
58+
* Creates new {@link AggregationExpression} that is a valid aggregation expression.
59+
*
60+
* @return new instance of {@link Expr}.
61+
*/
62+
public Expr expr() {
63+
return usesFieldRef() ? Expr.valueOf(fieldReference) : Expr.valueOf(expression);
64+
}
65+
66+
67+
public static class Expr extends AbstractAggregationExpression {
68+
69+
private Expr(Object value) {
70+
super(value);
71+
}
72+
73+
@Override
74+
protected String getMongoMethod() {
75+
return "$expr";
76+
}
77+
78+
/**
79+
* Creates new {@link Expr}.
80+
*
81+
* @param fieldReference must not be {@literal null}.
82+
* @return new instance of {@link Expr}.
83+
*/
84+
public static Expr valueOf(String fieldReference) {
85+
86+
Assert.notNull(fieldReference, "FieldReference must not be null!");
87+
return new Expr(Fields.field(fieldReference));
88+
}
89+
90+
/**
91+
* Creates new {@link Expr}.
92+
*
93+
* @param expression must not be {@literal null}.
94+
* @return new instance of {@link Expr}.
95+
*/
96+
public static Expr valueOf(AggregationExpression expression) {
97+
98+
Assert.notNull(expression, "Expression must not be null!");
99+
return new Expr(expression);
100+
}
101+
102+
}
103+
104+
private boolean usesFieldRef() {
105+
return fieldReference != null;
106+
}
107+
}
108+
109+
}

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

+37-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package org.springframework.data.mongodb.core.aggregation;
1717

1818
import org.bson.Document;
19+
import org.springframework.data.mongodb.core.aggregation.EvaluationOperators.EvaluationOperatorFactory.Expr;
1920
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
2021
import org.springframework.util.Assert;
2122

@@ -36,7 +37,16 @@
3637
public class MatchOperation implements AggregationOperation {
3738

3839
private final CriteriaDefinition criteriaDefinition;
39-
40+
private final AggregationExpression expression;
41+
42+
/**
43+
* Creates a new {@link MatchOperation}
44+
*/
45+
public MatchOperation() {
46+
this.criteriaDefinition = null;
47+
this.expression = null;
48+
}
49+
4050
/**
4151
* Creates a new {@link MatchOperation} for the given {@link CriteriaDefinition}.
4252
*
@@ -46,14 +56,39 @@ public MatchOperation(CriteriaDefinition criteriaDefinition) {
4656

4757
Assert.notNull(criteriaDefinition, "Criteria must not be null!");
4858
this.criteriaDefinition = criteriaDefinition;
59+
this.expression = null;
4960
}
50-
61+
62+
/**
63+
* Creates a new {@link MatchOperation} for the given {@link Expression}.
64+
*
65+
* @param criteriaDefinition must not be {@literal null}.
66+
*/
67+
private MatchOperation(Expr expression) {
68+
Assert.notNull(expression, "Expression must not be null!");
69+
this.criteriaDefinition = null;
70+
this.expression = expression;
71+
}
72+
73+
/**
74+
* Creates a new {@link MatchOperation} for the given {@link AggregationExpression}.
75+
*
76+
* @param expression must not be {@literal null}.
77+
*/
78+
public MatchOperation withValueOf(AggregationExpression expression) {
79+
Assert.notNull(expression, "Expression must not be null!");
80+
return new MatchOperation(EvaluationOperators.valueOf(expression).expr());
81+
}
82+
5183
/*
5284
* (non-Javadoc)
5385
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
5486
*/
5587
@Override
5688
public Document toDocument(AggregationOperationContext context) {
89+
if(expression != null) {
90+
return new Document(getOperator(), expression.toDocument());
91+
}
5792
return new Document(getOperator(), context.getMappedObject(criteriaDefinition.getCriteriaObject()));
5893
}
5994

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

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.List;
2222

2323
import org.bson.Document;
24+
2425
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
2526
import org.springframework.expression.spel.ast.Projection;
2627
import org.springframework.util.Assert;

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

+1
Original file line numberDiff line numberDiff line change
@@ -193,5 +193,6 @@ public interface ValueAppender {
193193
*/
194194
SetOperation withValueOfExpression(String operation, Object... values);
195195
}
196+
196197
}
197198
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package org.springframework.data.mongodb.core.aggregation;
2+
3+
import static org.assertj.core.api.Assertions.*;
4+
5+
import org.bson.Document;
6+
import org.junit.jupiter.api.Test;
7+
8+
class MatchOperationUnitTests {
9+
10+
@Test // DATAMONGO - 3729
11+
public void shouldRenderStdDevPopCorrectly() {
12+
MatchOperation operation = Aggregation.match().withValueOf(ArithmeticOperators.valueOf("quiz").stdDevPop());
13+
assertThat(operation.toDocument(Aggregation.DEFAULT_CONTEXT)).
14+
isEqualTo(Document.parse("{ $match: { \"$expr\" : { \"$stdDevPop\" : \"$quiz\" } } } "));
15+
16+
}
17+
18+
@Test // DATAMONGO - 3729
19+
public void shouldRenderStdDevSampCorrectly() {
20+
MatchOperation operation = Aggregation.match().withValueOf(ArithmeticOperators.valueOf("quiz").stdDevSamp());
21+
assertThat(operation.toDocument(Aggregation.DEFAULT_CONTEXT)).
22+
isEqualTo(Document.parse("{ $match: { \"$expr\" : { \"$stdDevSamp\" : \"$quiz\" } } } "));
23+
24+
}
25+
26+
}

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

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import org.bson.Document;
2323
import org.junit.jupiter.api.Test;
24+
2425
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
2526
import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver;
2627
import org.springframework.data.mongodb.core.convert.QueryMapper;

0 commit comments

Comments
 (0)