Skip to content

Commit e992d81

Browse files
mp911dechristophstrobl
authored andcommitted
DATAMONGO-1552 - Add $bucket aggregation stage.
Original Pull Request: #426
1 parent aa1e91c commit e992d81

File tree

5 files changed

+1253
-1
lines changed

5 files changed

+1253
-1
lines changed

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ public static ProjectionOperation project(String... fields) {
202202
}
203203

204204
/**
205-
* Creates a new {@link ProjectionOperation} includeing the given {@link Fields}.
205+
* Creates a new {@link ProjectionOperation} including the given {@link Fields}.
206206
*
207207
* @param fields must not be {@literal null}.
208208
* @return
@@ -418,6 +418,26 @@ public static OutOperation out(String outCollectionName) {
418418
return new OutOperation(outCollectionName);
419419
}
420420

421+
/**
422+
* Creates a new {@link BucketOperation} using given {@literal groupByField}.
423+
*
424+
* @param groupByField must not be {@literal null} or empty.
425+
* @return
426+
*/
427+
public static BucketOperation bucket(String groupByField) {
428+
return new BucketOperation(field(groupByField));
429+
}
430+
431+
/**
432+
* Creates a new {@link BucketOperation} using given {@link AggregationExpression group-by expression}.
433+
*
434+
* @param groupByExpression must not be {@literal null}.
435+
* @return
436+
*/
437+
public static BucketOperation bucket(AggregationExpression groupByExpression) {
438+
return new BucketOperation(groupByExpression);
439+
}
440+
421441
/**
422442
* Creates a new {@link LookupOperation}.
423443
*
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
/*
2+
* Copyright 2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.mongodb.core.aggregation;
17+
18+
import java.util.ArrayList;
19+
import java.util.Arrays;
20+
import java.util.Collections;
21+
import java.util.List;
22+
23+
import org.springframework.data.mongodb.core.aggregation.BucketOperation.BucketOperationOutputBuilder;
24+
import org.springframework.util.Assert;
25+
26+
import com.mongodb.BasicDBObject;
27+
import com.mongodb.DBObject;
28+
29+
/**
30+
* Encapsulates the aggregation framework {@code $bucket}-operation.
31+
* <p>
32+
* Bucket stage is typically used with {@link Aggregation} and {@code $facet}. Categorizes incoming documents into
33+
* groups, called buckets, based on a specified expression and bucket boundaries.
34+
* <p>
35+
* We recommend to use the static factory method {@link Aggregation#bucket(String)} instead of creating instances of
36+
* this class directly.
37+
*
38+
* @see http://docs.mongodb.org/manual/reference/aggregation/bucket/
39+
* @see BucketOperationSupport
40+
* @author Mark Paluch
41+
* @since 1.10
42+
*/
43+
public class BucketOperation extends BucketOperationSupport<BucketOperation, BucketOperationOutputBuilder>
44+
implements FieldsExposingAggregationOperation {
45+
46+
private final List<Object> boundaries;
47+
private final Object defaultBucket;
48+
49+
/**
50+
* Creates a new {@link BucketOperation} given a {@link Field group-by field}.
51+
*
52+
* @param groupByField must not be {@literal null}.
53+
*/
54+
public BucketOperation(Field groupByField) {
55+
56+
super(groupByField);
57+
58+
this.boundaries = Collections.emptyList();
59+
this.defaultBucket = null;
60+
}
61+
62+
/**
63+
* Creates a new {@link BucketOperation} given a {@link AggregationExpression group-by expression}.
64+
*
65+
* @param groupByExpression must not be {@literal null}.
66+
*/
67+
public BucketOperation(AggregationExpression groupByExpression) {
68+
69+
super(groupByExpression);
70+
71+
this.boundaries = Collections.emptyList();
72+
this.defaultBucket = null;
73+
}
74+
75+
private BucketOperation(BucketOperation bucketOperation, Outputs outputs) {
76+
77+
super(bucketOperation, outputs);
78+
79+
this.boundaries = bucketOperation.boundaries;
80+
this.defaultBucket = bucketOperation.defaultBucket;
81+
}
82+
83+
private BucketOperation(BucketOperation bucketOperation, List<Object> boundaries, Object defaultBucket) {
84+
85+
super(bucketOperation);
86+
87+
this.boundaries = new ArrayList<Object>(boundaries);
88+
this.defaultBucket = defaultBucket;
89+
}
90+
91+
/* (non-Javadoc)
92+
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
93+
*/
94+
@Override
95+
public DBObject toDBObject(AggregationOperationContext context) {
96+
97+
DBObject options = new BasicDBObject();
98+
99+
options.put("boundaries", context.getMappedObject(new BasicDBObject("$set", boundaries)).get("$set"));
100+
101+
if (defaultBucket != null) {
102+
options.put("default", context.getMappedObject(new BasicDBObject("$set", defaultBucket)).get("$set"));
103+
}
104+
105+
options.putAll(super.toDBObject(context));
106+
107+
return new BasicDBObject("$bucket", options);
108+
}
109+
110+
/**
111+
* Configures a default bucket {@literal literal} and return a new {@link BucketOperation}.
112+
*
113+
* @param literal must not be {@literal null}.
114+
* @return
115+
*/
116+
public BucketOperation withDefaultBucket(Object literal) {
117+
118+
Assert.notNull(literal, "Default bucket literal must not be null!");
119+
return new BucketOperation(this, boundaries, literal);
120+
}
121+
122+
/**
123+
* Configures {@literal boundaries} and return a new {@link BucketOperation}. Existing {@literal boundaries} are
124+
* preserved and the new {@literal boundaries} are appended.
125+
*
126+
* @param boundaries must not be {@literal null}.
127+
* @return
128+
*/
129+
public BucketOperation withBoundaries(Object... boundaries) {
130+
131+
Assert.notNull(boundaries, "Boundaries must not be null!");
132+
133+
List<Object> newBoundaries = new ArrayList<Object>(this.boundaries.size() + boundaries.length);
134+
newBoundaries.addAll(this.boundaries);
135+
newBoundaries.addAll(Arrays.asList(boundaries));
136+
137+
return new BucketOperation(this, newBoundaries, defaultBucket);
138+
}
139+
140+
/* (non-Javadoc)
141+
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#newBucketOperation(org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.Outputs)
142+
*/
143+
@Override
144+
protected BucketOperation newBucketOperation(Outputs outputs) {
145+
return new BucketOperation(this, outputs);
146+
}
147+
148+
/* (non-Javadoc)
149+
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#andOutputExpression(java.lang.String, java.lang.Object[])
150+
*/
151+
@Override
152+
public ExpressionBucketOperationBuilder andOutputExpression(String expression, Object... params) {
153+
return new ExpressionBucketOperationBuilder(expression, this, params);
154+
}
155+
156+
/* (non-Javadoc)
157+
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#andOutput(org.springframework.data.mongodb.core.aggregation.AggregationExpression)
158+
*/
159+
@Override
160+
public BucketOperationOutputBuilder andOutput(AggregationExpression expression) {
161+
return new BucketOperationOutputBuilder(expression, this);
162+
}
163+
164+
/* (non-Javadoc)
165+
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#andOutput(java.lang.String)
166+
*/
167+
@Override
168+
public BucketOperationOutputBuilder andOutput(String fieldName) {
169+
return new BucketOperationOutputBuilder(Fields.field(fieldName), this);
170+
}
171+
172+
/**
173+
* {@link OutputBuilder} implementation for {@link BucketOperation}.
174+
*/
175+
public static class BucketOperationOutputBuilder
176+
extends BucketOperationSupport.OutputBuilder<BucketOperationOutputBuilder, BucketOperation> {
177+
178+
/**
179+
* Creates a new {@link BucketOperationOutputBuilder} fot the given value and {@link BucketOperation}.
180+
*
181+
* @param value must not be {@literal null}.
182+
* @param operation must not be {@literal null}.
183+
*/
184+
protected BucketOperationOutputBuilder(Object value, BucketOperation operation) {
185+
super(value, operation);
186+
}
187+
188+
/* (non-Javadoc)
189+
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.OutputBuilder#apply(org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.OperationOutput)
190+
*/
191+
@Override
192+
protected BucketOperationOutputBuilder apply(OperationOutput operationOutput) {
193+
return new BucketOperationOutputBuilder(operationOutput, this.operation);
194+
}
195+
}
196+
197+
/**
198+
* {@link ExpressionBucketOperationBuilderSupport} implementation for {@link BucketOperation} using SpEL expression
199+
* based {@link Output}.
200+
*
201+
* @author Mark Paluch
202+
*/
203+
public static class ExpressionBucketOperationBuilder
204+
extends ExpressionBucketOperationBuilderSupport<BucketOperationOutputBuilder, BucketOperation> {
205+
206+
/**
207+
* Creates a new {@link ExpressionBucketOperationBuilderSupport} for the given value, {@link BucketOperation}
208+
* and parameters.
209+
*
210+
* @param expression must not be {@literal null}.
211+
* @param operation must not be {@literal null}.
212+
* @param parameters
213+
*/
214+
protected ExpressionBucketOperationBuilder(String expression, BucketOperation operation, Object[] parameters) {
215+
super(expression, operation, parameters);
216+
}
217+
218+
/* (non-Javadoc)
219+
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.OutputBuilder#apply(org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.OperationOutput)
220+
*/
221+
@Override
222+
protected BucketOperationOutputBuilder apply(OperationOutput operationOutput) {
223+
return new BucketOperationOutputBuilder(operationOutput, this.operation);
224+
}
225+
}
226+
}

0 commit comments

Comments
 (0)