Skip to content

Commit 8b3da2d

Browse files
Thomas Darimontodrotbohm
Thomas Darimont
authored andcommitted
DATAMONGO-788 - Projection operations do not render synthetic fields properly.
Introduced boolean isSynthetic() attribute to FieldReference to determine if the given reference points to a synthetic field, as this controls whether we render a simple include (1) or a concrete reference ($fieldName) E.g. isSynthetic() would be true for a field reference to _id. Original pull request: #90.
1 parent 49af31b commit 8b3da2d

File tree

4 files changed

+83
-1
lines changed

4 files changed

+83
-1
lines changed

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

+7
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,13 @@ public FieldReference(ExposedField field) {
334334
this.field = field;
335335
}
336336

337+
/**
338+
* @return
339+
*/
340+
public boolean isSynthetic() {
341+
return field.synthetic;
342+
}
343+
337344
/**
338345
* Returns the raw, unqualified reference, i.e. the field reference without a {@literal $} prefix.
339346
*

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,7 @@ private Object renderFieldValue(AggregationOperationContext context) {
508508
// check whether referenced field exists in the context
509509
FieldReference reference = context.getReference(field.getTarget());
510510

511-
if (field.getName().equals(field.getTarget())) {
511+
if (field.getName().equals(field.getTarget()) && reference.isSynthetic()) {
512512

513513
// render field as included
514514
return 1;

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

+49
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ private void cleanDb() {
8585
mongoTemplate.dropCollection(Product.class);
8686
mongoTemplate.dropCollection(UserWithLikes.class);
8787
mongoTemplate.dropCollection(DATAMONGO753.class);
88+
mongoTemplate.dropCollection(DATAMONGO788.class);
8889
}
8990

9091
/**
@@ -520,6 +521,36 @@ public void aliasesNestedFieldInProjectionImmediately() {
520521
}
521522
}
522523

524+
/**
525+
* @see DATAMONGO-788
526+
*/
527+
@Test
528+
public void referencesToGroupIdsShouldBeRenderedProperly() {
529+
530+
mongoTemplate.insert(new DATAMONGO788(1, 1));
531+
mongoTemplate.insert(new DATAMONGO788(1, 1));
532+
mongoTemplate.insert(new DATAMONGO788(1, 1));
533+
mongoTemplate.insert(new DATAMONGO788(2, 1));
534+
mongoTemplate.insert(new DATAMONGO788(2, 1));
535+
536+
AggregationOperation projectFirst = Aggregation.project("x", "y").and("xField").as("x").and("yField").as("y");
537+
AggregationOperation group = Aggregation.group("x", "y").count().as("xPerY");
538+
AggregationOperation project = Aggregation.project("xPerY", "x", "y").andExclude("_id");
539+
540+
TypedAggregation<DATAMONGO788> aggregation = Aggregation.newAggregation(DATAMONGO788.class, projectFirst, group,
541+
project);
542+
AggregationResults<DBObject> aggResults = mongoTemplate.aggregate(aggregation, DBObject.class);
543+
List<DBObject> items = aggResults.getMappedResults();
544+
545+
assertThat(items.size(), is(2));
546+
assertThat((Integer) items.get(0).get("xPerY"), is(2));
547+
assertThat((Integer) items.get(0).get("x"), is(2));
548+
assertThat((Integer) items.get(0).get("y"), is(1));
549+
assertThat((Integer) items.get(1).get("xPerY"), is(3));
550+
assertThat((Integer) items.get(1).get("x"), is(1));
551+
assertThat((Integer) items.get(1).get("y"), is(1));
552+
}
553+
523554
private void assertLikeStats(LikeStats like, String id, long count) {
524555

525556
assertThat(like, is(notNullValue()));
@@ -585,4 +616,22 @@ public PD(String pDch, int up) {
585616
this.up = up;
586617
}
587618
}
619+
620+
static class DATAMONGO788 {
621+
622+
int x;
623+
int y;
624+
int xField;
625+
int yField;
626+
627+
public DATAMONGO788() {}
628+
629+
public DATAMONGO788(int x, int y) {
630+
this.x = x;
631+
this.xField = x;
632+
this.y = y;
633+
this.yField = y;
634+
}
635+
}
636+
588637
}

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

+26
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,19 @@
1515
*/
1616
package org.springframework.data.mongodb.core.aggregation;
1717

18+
import static org.hamcrest.CoreMatchers.*;
19+
import static org.junit.Assert.*;
1820
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
1921
import static org.springframework.data.mongodb.core.query.Criteria.*;
2022

23+
import java.util.List;
24+
2125
import org.junit.Rule;
2226
import org.junit.Test;
2327
import org.junit.rules.ExpectedException;
28+
import org.springframework.data.mongodb.core.DBObjectUtils;
29+
30+
import com.mongodb.DBObject;
2431

2532
/**
2633
* Unit tests for {@link Aggregation}.
@@ -94,4 +101,23 @@ public void matchOperationShouldNotChangeAvailableFields() {
94101
project("a", "b") // b should still be available
95102
).toDbObject("foo", Aggregation.DEFAULT_CONTEXT);
96103
}
104+
105+
/**
106+
* @see DATAMONGO-788
107+
*/
108+
@Test
109+
public void referencesToGroupIdsShouldBeRenderedAsReferences() {
110+
111+
DBObject agg = newAggregation( //
112+
project("a"), //
113+
group("a").count().as("aCnt"), //
114+
project("aCnt", "a") //
115+
).toDbObject("foo", Aggregation.DEFAULT_CONTEXT);
116+
117+
@SuppressWarnings("unchecked")
118+
DBObject secondProjection = ((List<DBObject>) agg.get("pipeline")).get(2);
119+
DBObject fields = DBObjectUtils.getAsDBObject(secondProjection, "$project");
120+
assertThat((Integer) fields.get("aCnt"), is(1));
121+
assertThat((String) fields.get("a"), is("$_id.a"));
122+
}
97123
}

0 commit comments

Comments
 (0)