From 8b3da2d7f926ce2caeba6148524eca6ce800bfc8 Mon Sep 17 00:00:00 2001 From: Thomas Darimont Date: Thu, 31 Oct 2013 14:16:49 +0000 Subject: [PATCH] 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. --- .../core/aggregation/ExposedFields.java | 7 +++ .../core/aggregation/ProjectionOperation.java | 2 +- .../core/aggregation/AggregationTests.java | 49 +++++++++++++++++++ .../aggregation/AggregationUnitTests.java | 26 ++++++++++ 4 files changed, 83 insertions(+), 1 deletion(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ExposedFields.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ExposedFields.java index 0529c5110..4a5d7610b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ExposedFields.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ExposedFields.java @@ -334,6 +334,13 @@ public class ExposedFields implements Iterable { this.field = field; } + /** + * @return + */ + public boolean isSynthetic() { + return field.synthetic; + } + /** * Returns the raw, unqualified reference, i.e. the field reference without a {@literal $} prefix. * diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperation.java index 16ed45afd..d029a45a7 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperation.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperation.java @@ -508,7 +508,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { // check whether referenced field exists in the context FieldReference reference = context.getReference(field.getTarget()); - if (field.getName().equals(field.getTarget())) { + if (field.getName().equals(field.getTarget()) && reference.isSynthetic()) { // render field as included return 1; diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java index b7534f5f6..0777d68e4 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java @@ -85,6 +85,7 @@ public class AggregationTests { mongoTemplate.dropCollection(Product.class); mongoTemplate.dropCollection(UserWithLikes.class); mongoTemplate.dropCollection(DATAMONGO753.class); + mongoTemplate.dropCollection(DATAMONGO788.class); } /** @@ -520,6 +521,36 @@ public class AggregationTests { } } + /** + * @see DATAMONGO-788 + */ + @Test + public void referencesToGroupIdsShouldBeRenderedProperly() { + + mongoTemplate.insert(new DATAMONGO788(1, 1)); + mongoTemplate.insert(new DATAMONGO788(1, 1)); + mongoTemplate.insert(new DATAMONGO788(1, 1)); + mongoTemplate.insert(new DATAMONGO788(2, 1)); + mongoTemplate.insert(new DATAMONGO788(2, 1)); + + AggregationOperation projectFirst = Aggregation.project("x", "y").and("xField").as("x").and("yField").as("y"); + AggregationOperation group = Aggregation.group("x", "y").count().as("xPerY"); + AggregationOperation project = Aggregation.project("xPerY", "x", "y").andExclude("_id"); + + TypedAggregation aggregation = Aggregation.newAggregation(DATAMONGO788.class, projectFirst, group, + project); + AggregationResults aggResults = mongoTemplate.aggregate(aggregation, DBObject.class); + List items = aggResults.getMappedResults(); + + assertThat(items.size(), is(2)); + assertThat((Integer) items.get(0).get("xPerY"), is(2)); + assertThat((Integer) items.get(0).get("x"), is(2)); + assertThat((Integer) items.get(0).get("y"), is(1)); + assertThat((Integer) items.get(1).get("xPerY"), is(3)); + assertThat((Integer) items.get(1).get("x"), is(1)); + assertThat((Integer) items.get(1).get("y"), is(1)); + } + private void assertLikeStats(LikeStats like, String id, long count) { assertThat(like, is(notNullValue())); @@ -585,4 +616,22 @@ public class AggregationTests { this.up = up; } } + + static class DATAMONGO788 { + + int x; + int y; + int xField; + int yField; + + public DATAMONGO788() {} + + public DATAMONGO788(int x, int y) { + this.x = x; + this.xField = x; + this.y = y; + this.yField = y; + } + } + } 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 31251b16a..4951c246b 100644 --- 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 @@ -15,12 +15,19 @@ */ package org.springframework.data.mongodb.core.aggregation; +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; import static org.springframework.data.mongodb.core.query.Criteria.*; +import java.util.List; + import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.data.mongodb.core.DBObjectUtils; + +import com.mongodb.DBObject; /** * Unit tests for {@link Aggregation}. @@ -94,4 +101,23 @@ public class AggregationUnitTests { project("a", "b") // b should still be available ).toDbObject("foo", Aggregation.DEFAULT_CONTEXT); } + + /** + * @see DATAMONGO-788 + */ + @Test + public void referencesToGroupIdsShouldBeRenderedAsReferences() { + + DBObject agg = newAggregation( // + project("a"), // + group("a").count().as("aCnt"), // + project("aCnt", "a") // + ).toDbObject("foo", Aggregation.DEFAULT_CONTEXT); + + @SuppressWarnings("unchecked") + DBObject secondProjection = ((List) agg.get("pipeline")).get(2); + DBObject fields = DBObjectUtils.getAsDBObject(secondProjection, "$project"); + assertThat((Integer) fields.get("aCnt"), is(1)); + assertThat((String) fields.get("a"), is("$_id.a")); + } }