From 9d51ea4c017d143ff1e16f6e43bf60c13447814a Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Thu, 7 Jul 2016 14:41:12 +0200 Subject: [PATCH] DATAMONGO-1457 - Add support for $slice in aggregation. We now support $slice in aggregation projections via the ProjectionOperationBuilder. Aggregation.project().and("field").slice(10, 20) Original pull request: #372. --- .../core/aggregation/ProjectionOperation.java | 28 +++++++++++++++- .../core/aggregation/AggregationTests.java | 21 ++++++++++++ .../ProjectionOperationUnitTests.java | 33 ++++++++++++++++++- .../core/aggregation/UserWithLikes.java | 9 ++++- 4 files changed, 88 insertions(+), 3 deletions(-) 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 68947352a..7d71cc1e1 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 @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -352,6 +352,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { * * @author Oliver Gierke * @author Thomas Darimont + * @author Christoph Strobl */ public static class ProjectionOperationBuilder extends AbstractProjectionOperationBuilder { @@ -566,6 +567,31 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { return project("size"); } + /** + * Generates a {@code $slice} expression that returns a subset of the array held by the given field.
+ * If {@literal n} is positive, $slice returns up to the first n elements in the array.
+ * If {@literal n} is negative, $slice returns up to the last n elements in the array. + * + * @param count max number of elements. + * @return never {@literal null}. + * @since 1.10 + */ + public ProjectionOperationBuilder slice(int count) { + return project("slice", count); + } + + /** + * Generates a {@code $slice} expression that returns a subset of the array held by the given field.
+ * + * @param count max number of elements. Must not be negative. + * @param offset the offset within the array to start from. + * @return never {@literal null}. + * @since 1.10 + */ + public ProjectionOperationBuilder slice(int count, int offset) { + return project("slice", offset, count); + } + /* * (non-Javadoc) * @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext) 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 1de24d41b..b9ec9d853 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 @@ -1228,6 +1228,27 @@ public class AggregationTests { skip(100)); } + /** + * @see DATAMONGO-1457 + */ + @Test + public void sliceShouldBeAppliedCorrectly() { + + assumeTrue(mongoVersion.isGreaterThanOrEqualTo(THREE_DOT_TWO)); + + createUserWithLikesDocuments(); + + TypedAggregation agg = newAggregation(UserWithLikes.class, match(new Criteria()), + project().and("likes").slice(2)); + + AggregationResults result = mongoTemplate.aggregate(agg, UserWithLikes.class); + + assertThat(result.getMappedResults(), hasSize(9)); + for (UserWithLikes user : result) { + assertThat(user.likes.size() <= 2, is(true)); + } + } + private void createUsersWithReferencedPersons() { mongoTemplate.dropCollection(User.class); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperationUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperationUnitTests.java index 2f826ff93..bc1a06e51 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperationUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperationUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +36,7 @@ import com.mongodb.DBObject; * * @author Oliver Gierke * @author Thomas Darimont + * @author Christoph Strobl */ public class ProjectionOperationUnitTests { @@ -371,6 +372,36 @@ public class ProjectionOperationUnitTests { assertThat(projected.get("tags_count"), is((Object) new BasicDBObject("$size", Arrays.asList("$tags")))); } + /** + * @see DATAMONGO-1457 + */ + @Test + public void shouldRenderSliceCorrectly() throws Exception { + + ProjectionOperation operation = Aggregation.project().and("field").slice(10).as("renamed"); + + DBObject dbObject = operation.toDBObject(Aggregation.DEFAULT_CONTEXT); + DBObject projected = exctractOperation("$project", dbObject); + + assertThat(projected.get("renamed"), + is((Object) new BasicDBObject("$slice", Arrays. asList("$field", 10)))); + } + + /** + * @see DATAMONGO-1457 + */ + @Test + public void shouldRenderSliceWithPositionCorrectly() throws Exception { + + ProjectionOperation operation = Aggregation.project().and("field").slice(10, 5).as("renamed"); + + DBObject dbObject = operation.toDBObject(Aggregation.DEFAULT_CONTEXT); + DBObject projected = exctractOperation("$project", dbObject); + + assertThat(projected.get("renamed"), + is((Object) new BasicDBObject("$slice", Arrays. asList("$field", 5, 10)))); + } + private static DBObject exctractOperation(String field, DBObject fromProjectClause) { return (DBObject) fromProjectClause.get(field); } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/UserWithLikes.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/UserWithLikes.java index 8398ed29d..336762071 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/UserWithLikes.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/UserWithLikes.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2013-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,9 +20,15 @@ import java.util.Date; import java.util.HashSet; import java.util.Set; +import lombok.Data; +import lombok.NoArgsConstructor; + /** * @author Thomas Darimont + * @author Christoph Strobl */ +@Data +@NoArgsConstructor public class UserWithLikes { String id; @@ -30,6 +36,7 @@ public class UserWithLikes { Set likes = new HashSet(); public UserWithLikes(String id, Date joined, String... likes) { + this.id = id; this.joined = joined; this.likes = new HashSet(Arrays.asList(likes));