DATAMONGO-1552 - Add $bucketAuto aggregation stage.
Original Pull Request: #426
This commit is contained in:
committed by
Christoph Strobl
parent
5c5c616be9
commit
b7a0b1d523
@@ -417,7 +417,7 @@ public class Aggregation {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketOperation} using given {@literal groupByField}.
|
||||
* Creates a new {@link BucketOperation} given {@literal groupByField}.
|
||||
*
|
||||
* @param groupByField must not be {@literal null} or empty.
|
||||
* @return
|
||||
@@ -427,7 +427,7 @@ public class Aggregation {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketOperation} using given {@link AggregationExpression group-by expression}.
|
||||
* Creates a new {@link BucketOperation} given {@link AggregationExpression group-by expression}.
|
||||
*
|
||||
* @param groupByExpression must not be {@literal null}.
|
||||
* @return
|
||||
@@ -436,6 +436,28 @@ public class Aggregation {
|
||||
return new BucketOperation(groupByExpression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketAutoOperation} given {@literal groupByField}.
|
||||
*
|
||||
* @param groupByField must not be {@literal null} or empty.
|
||||
* @param buckets number of buckets, must be a positive integer.
|
||||
* @return
|
||||
*/
|
||||
public static BucketAutoOperation bucketAuto(String groupByField, int buckets) {
|
||||
return new BucketAutoOperation(field(groupByField), buckets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketAutoOperation} given {@link AggregationExpression group-by expression}.
|
||||
*
|
||||
* @param groupByExpression must not be {@literal null}.
|
||||
* @param buckets number of buckets, must be a positive integer.
|
||||
* @return
|
||||
*/
|
||||
public static BucketAutoOperation bucketAuto(AggregationExpression groupByExpression, int buckets) {
|
||||
return new BucketAutoOperation(groupByExpression, buckets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link LookupOperation}.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import org.springframework.data.mongodb.core.aggregation.BucketAutoOperation.BucketAutoOperationOutputBuilder;
|
||||
import org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.OutputBuilder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.bson.Document;
|
||||
|
||||
/**
|
||||
* Encapsulates the aggregation framework {@code $bucketAuto}-operation.
|
||||
* <p>
|
||||
* Bucket stage is typically used with {@link Aggregation} and {@code $facet}. Categorizes incoming documents into a
|
||||
* specific number of groups, called buckets, based on a specified expression. Bucket boundaries are automatically
|
||||
* determined in an attempt to evenly distribute the documents into the specified number of buckets.
|
||||
* <p>
|
||||
* We recommend to use the static factory method {@link Aggregation#bucketAuto(String, int)} instead of creating instances of
|
||||
* this class directly.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/aggregation/bucketAuto/
|
||||
* @see BucketOperationSupport
|
||||
* @author Mark Paluch
|
||||
* @since 1.10
|
||||
*/
|
||||
public class BucketAutoOperation extends BucketOperationSupport<BucketAutoOperation, BucketAutoOperationOutputBuilder>
|
||||
implements FieldsExposingAggregationOperation {
|
||||
|
||||
private final int buckets;
|
||||
private final String granularity;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketAutoOperation} given a {@link Field group-by field}.
|
||||
*
|
||||
* @param groupByField must not be {@literal null}.
|
||||
* @param buckets number of buckets, must be a positive integer.
|
||||
*/
|
||||
public BucketAutoOperation(Field groupByField, int buckets) {
|
||||
|
||||
super(groupByField);
|
||||
|
||||
Assert.isTrue(buckets > 0, "Number of buckets must be greater 0!");
|
||||
|
||||
this.buckets = buckets;
|
||||
this.granularity = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketAutoOperation} given a {@link AggregationExpression group-by expression}.
|
||||
*
|
||||
* @param groupByExpression must not be {@literal null}.
|
||||
* @param buckets number of buckets, must be a positive integer.
|
||||
*/
|
||||
public BucketAutoOperation(AggregationExpression groupByExpression, int buckets) {
|
||||
|
||||
super(groupByExpression);
|
||||
|
||||
Assert.isTrue(buckets > 0, "Number of buckets must be greater 0!");
|
||||
|
||||
this.buckets = buckets;
|
||||
this.granularity = null;
|
||||
}
|
||||
|
||||
private BucketAutoOperation(BucketAutoOperation bucketOperation, Outputs outputs) {
|
||||
|
||||
super(bucketOperation, outputs);
|
||||
|
||||
this.buckets = bucketOperation.buckets;
|
||||
this.granularity = bucketOperation.granularity;
|
||||
}
|
||||
|
||||
private BucketAutoOperation(BucketAutoOperation bucketOperation, int buckets, String granularity) {
|
||||
|
||||
super(bucketOperation);
|
||||
|
||||
this.buckets = buckets;
|
||||
this.granularity = granularity;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
|
||||
Document options = new Document();
|
||||
|
||||
options.put("buckets", buckets);
|
||||
|
||||
if (granularity != null) {
|
||||
options.put("granularity", granularity);
|
||||
}
|
||||
|
||||
options.putAll(super.toDocument(context));
|
||||
|
||||
return new Document("$bucketAuto", options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a number of bucket {@literal buckets} and return a new {@link BucketAutoOperation}.
|
||||
*
|
||||
* @param buckets must be a positive number.
|
||||
* @return
|
||||
*/
|
||||
public BucketAutoOperation withBuckets(int buckets) {
|
||||
|
||||
Assert.isTrue(buckets > 0, "Number of buckets must be greater 0!");
|
||||
return new BucketAutoOperation(this, buckets, granularity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures {@literal granularity} that specifies the preferred number series to use to ensure that the calculated
|
||||
* boundary edges end on preferred round numbers or their powers of 10 and return a new {@link BucketAutoOperation}.
|
||||
*
|
||||
* @param granularity must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public BucketAutoOperation withGranularity(Granularity granularity) {
|
||||
|
||||
Assert.notNull(granularity, "Granularity must not be null!");
|
||||
|
||||
return new BucketAutoOperation(this, buckets, granularity.toMongoGranularity());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#newBucketOperation(org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.Outputs)
|
||||
*/
|
||||
@Override
|
||||
protected BucketAutoOperation newBucketOperation(Outputs outputs) {
|
||||
return new BucketAutoOperation(this, outputs);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#andOutputExpression(java.lang.String, java.lang.Object[])
|
||||
*/
|
||||
@Override
|
||||
public ExpressionBucketAutoOperationBuilder andOutputExpression(String expression, Object... params) {
|
||||
return new ExpressionBucketAutoOperationBuilder(expression, this, params);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#andOutput(org.springframework.data.mongodb.core.aggregation.AggregationExpression)
|
||||
*/
|
||||
@Override
|
||||
public BucketAutoOperationOutputBuilder andOutput(AggregationExpression expression) {
|
||||
return new BucketAutoOperationOutputBuilder(expression, this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#andOutput(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public BucketAutoOperationOutputBuilder andOutput(String fieldName) {
|
||||
return new BucketAutoOperationOutputBuilder(Fields.field(fieldName), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link OutputBuilder} implementation for {@link BucketAutoOperation}.
|
||||
*/
|
||||
public static class BucketAutoOperationOutputBuilder
|
||||
extends OutputBuilder<BucketAutoOperationOutputBuilder, BucketAutoOperation> {
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketAutoOperationOutputBuilder} fot the given value and {@link BucketAutoOperation}.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @param operation must not be {@literal null}.
|
||||
*/
|
||||
protected BucketAutoOperationOutputBuilder(Object value, BucketAutoOperation operation) {
|
||||
super(value, operation);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.OutputBuilder#apply(org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.OperationOutput)
|
||||
*/
|
||||
@Override
|
||||
protected BucketAutoOperationOutputBuilder apply(OperationOutput operationOutput) {
|
||||
return new BucketAutoOperationOutputBuilder(operationOutput, this.operation);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ExpressionBucketOperationBuilderSupport} implementation for {@link BucketAutoOperation} using SpEL
|
||||
* expression based {@link Output}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public static class ExpressionBucketAutoOperationBuilder
|
||||
extends ExpressionBucketOperationBuilderSupport<BucketAutoOperationOutputBuilder, BucketAutoOperation> {
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExpressionBucketAutoOperationBuilder} for the given value, {@link BucketAutoOperation} and
|
||||
* parameters.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @param operation must not be {@literal null}.
|
||||
* @param parameters
|
||||
*/
|
||||
protected ExpressionBucketAutoOperationBuilder(String expression, BucketAutoOperation operation,
|
||||
Object[] parameters) {
|
||||
super(expression, operation, parameters);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.OutputBuilder#apply(org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.OperationOutput)
|
||||
*/
|
||||
@Override
|
||||
protected BucketAutoOperationOutputBuilder apply(OperationOutput operationOutput) {
|
||||
return new BucketAutoOperationOutputBuilder(operationOutput, this.operation);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public static interface Granularity {
|
||||
|
||||
/**
|
||||
* @return a String that represents a MongoDB granularity to be used with {@link BucketAutoOperation}.
|
||||
*/
|
||||
String toMongoGranularity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Supported MongoDB granularities.
|
||||
*
|
||||
* @see https://en.wikipedia.org/wiki/Preferred_number
|
||||
* @see https://docs.mongodb.com/manual/reference/operator/aggregation/bucketAuto/#granularity
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public enum Granularities implements Granularity {
|
||||
|
||||
R5, R10, R20, R40, R80, //
|
||||
|
||||
SERIES_1_2_5("1-2-5"), //
|
||||
|
||||
E6, E12, E24, E48, E96, E192, //
|
||||
|
||||
POWERSOF2;
|
||||
|
||||
final String granularity;
|
||||
|
||||
Granularities() {
|
||||
this.granularity = name();
|
||||
}
|
||||
|
||||
Granularities(String granularity) {
|
||||
this.granularity = granularity;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.GranularitytoMongoGranularity()
|
||||
*/
|
||||
@Override
|
||||
public String toMongoGranularity() {
|
||||
return granularity;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -221,7 +221,7 @@ public abstract class BucketOperationSupport<T extends BucketOperationSupport<T,
|
||||
* @param value must not be {@literal null}.
|
||||
* @param operation must not be {@literal null}.
|
||||
*/
|
||||
public OutputBuilder(Object value, T operation) {
|
||||
protected OutputBuilder(Object value, T operation) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null or empty!");
|
||||
Assert.notNull(operation, "ProjectionOperation must not be null!");
|
||||
@@ -432,6 +432,11 @@ public abstract class BucketOperationSupport<T extends BucketOperationSupport<T,
|
||||
*/
|
||||
protected ExposedFields asExposedFields() {
|
||||
|
||||
// The count field is included by default when the output is not specified.
|
||||
if (isEmpty()) {
|
||||
return ExposedFields.from(new ExposedField("count", true));
|
||||
}
|
||||
|
||||
ExposedFields fields = ExposedFields.from();
|
||||
|
||||
for (Output output : outputs) {
|
||||
|
||||
@@ -62,7 +62,9 @@ import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.ConditionalOperators;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Let;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Let.ExpressionVariable;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Multiply;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationTests.CarDescriptor.Entry;
|
||||
import org.springframework.data.mongodb.core.aggregation.BucketAutoOperation.Granularities;
|
||||
import org.springframework.data.mongodb.core.index.GeospatialIndex;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.NearQuery;
|
||||
@@ -1702,6 +1704,43 @@ public class AggregationTests {
|
||||
assertThat((Double) bound100.get("sum"), is(closeTo(3672.9, 0.1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1552
|
||||
*/
|
||||
@Test
|
||||
public void bucketAutoShouldCollectDocumentsIntoABucket() {
|
||||
|
||||
assumeTrue(mongoVersion.isGreaterThanOrEqualTo(THREE_DOT_FOUR));
|
||||
|
||||
Art a1 = Art.builder().id(1).title("The Pillars of Society").artist("Grosz").year(1926).price(199.99).build();
|
||||
Art a2 = Art.builder().id(2).title("Melancholy III").artist("Munch").year(1902).price(280.00).build();
|
||||
Art a3 = Art.builder().id(3).title("Dancer").artist("Miro").year(1925).price(76.04).build();
|
||||
Art a4 = Art.builder().id(4).title("The Great Wave off Kanagawa").artist("Hokusai").price(167.30).build();
|
||||
|
||||
mongoTemplate.insert(Arrays.asList(a1, a2, a3, a4), Art.class);
|
||||
|
||||
TypedAggregation<Art> aggregation = newAggregation(Art.class, //
|
||||
bucketAuto(Multiply.valueOf("price").multiplyBy(10), 3) //
|
||||
.withGranularity(Granularities.E12) //
|
||||
.andOutputCount().as("count") //
|
||||
.andOutput("title").push().as("titles") //
|
||||
.andOutputExpression("price * 10").sum().as("sum"));
|
||||
|
||||
AggregationResults<Document> result = mongoTemplate.aggregate(aggregation, Document.class);
|
||||
assertThat(result.getMappedResults().size(), is(3));
|
||||
|
||||
// { "min" : 680.0 , "max" : 820.0 , "count" : 1 , "titles" : [ "Dancer"] , "sum" : 760.4000000000001}
|
||||
Document bound0 = result.getMappedResults().get(0);
|
||||
assertThat(bound0, isBsonObject().containing("count", 1).containing("titles.[0]", "Dancer").containing("min", 680.0)
|
||||
.containing("max"));
|
||||
|
||||
// { "min" : 820.0 , "max" : 1800.0 , "count" : 1 , "titles" : [ "The Great Wave off Kanagawa"] , "sum" : 1673.0}
|
||||
Document bound1 = result.getMappedResults().get(1);
|
||||
assertThat(bound1, isBsonObject().containing("count", 1).containing("min", 820.0));
|
||||
assertThat((List<String>) bound1.get("titles"), hasItems("The Great Wave off Kanagawa"));
|
||||
assertThat((Double) bound1.get("sum"), is(closeTo(1673.0, 0.1)));
|
||||
}
|
||||
|
||||
private void createUsersWithReferencedPersons() {
|
||||
|
||||
mongoTemplate.dropCollection(User.class);
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import static org.hamcrest.core.Is.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.mongodb.core.DocumentTestUtils.getAsDocument;
|
||||
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.mongodb.core.aggregation.BucketAutoOperation.Granularities;
|
||||
|
||||
import org.bson.Document;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link BucketAutoOperation}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class BucketAutoOperationUnitTests {
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1552
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsNullFields() {
|
||||
new BucketAutoOperation((Field) null, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1552
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsNonPositiveIntegerNullFields() {
|
||||
new BucketAutoOperation(Fields.field("field"), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1552
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderBucketOutputExpressions() {
|
||||
|
||||
BucketAutoOperation operation = Aggregation.bucketAuto("field", 5) //
|
||||
.andOutputExpression("(netPrice + surCharge) * taxrate * [0]", 2).as("grossSalesPrice") //
|
||||
.andOutput("title").push().as("titles");
|
||||
|
||||
Document agg = operation.toDocument(Aggregation.DEFAULT_CONTEXT);
|
||||
assertThat(extractOutput(agg), is(Document.parse(
|
||||
"{ \"grossSalesPrice\" : { \"$multiply\" : [ { \"$add\" : [ \"$netPrice\" , \"$surCharge\"]} , \"$taxrate\" , 2]} , \"titles\" : { $push: \"$title\" } }}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1552
|
||||
*/
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void shouldRenderEmptyAggregationExpression() {
|
||||
bucket("groupby").andOutput("field").as("alias");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1552
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderBucketOutputOperators() {
|
||||
|
||||
BucketAutoOperation operation = Aggregation.bucketAuto("field", 5) //
|
||||
.andOutputCount().as("titles");
|
||||
|
||||
Document agg = operation.toDocument(Aggregation.DEFAULT_CONTEXT);
|
||||
assertThat(extractOutput(agg), is(Document.parse("{ titles : { $sum: 1 } }")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1552
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderCorrectly() {
|
||||
|
||||
Document agg = bucketAuto("field", 1).withBuckets(5).toDocument(Aggregation.DEFAULT_CONTEXT);
|
||||
|
||||
assertThat(agg, is(Document.parse("{ $bucketAuto: { groupBy: \"$field\", buckets: 5 } }")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1552
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderGranulariy() {
|
||||
|
||||
Document agg = bucketAuto("field", 1) //
|
||||
.withGranularity(Granularities.E24) //
|
||||
.toDocument(Aggregation.DEFAULT_CONTEXT);
|
||||
|
||||
assertThat(agg, is(Document.parse("{ $bucketAuto: { buckets: 1, granularity: \"E24\", groupBy: \"$field\" } }")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1552
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderSumOperator() {
|
||||
|
||||
BucketAutoOperation operation = bucketAuto("field", 5) //
|
||||
.andOutput("score").sum().as("cummulated_score");
|
||||
|
||||
Document agg = operation.toDocument(Aggregation.DEFAULT_CONTEXT);
|
||||
assertThat(extractOutput(agg), is(Document.parse("{ cummulated_score : { $sum: \"$score\" } }")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1552
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderSumWithOwnOutputExpression() {
|
||||
|
||||
BucketAutoOperation operation = bucketAuto("field", 5) //
|
||||
.andOutputExpression("netPrice + tax").apply("$multiply", 5).as("total");
|
||||
|
||||
Document agg = operation.toDocument(Aggregation.DEFAULT_CONTEXT);
|
||||
assertThat(extractOutput(agg),
|
||||
is(Document.parse("{ total : { $multiply: [ {$add : [\"$netPrice\", \"$tax\"]}, 5] } }")));
|
||||
}
|
||||
|
||||
private static Document extractOutput(Document fromBucketClause) {
|
||||
return getAsDocument(getAsDocument(fromBucketClause, "$bucketAuto"), "output");
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import static org.hamcrest.core.Is.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
|
||||
|
||||
@@ -247,6 +248,18 @@ public class BucketOperationUnitTests {
|
||||
is(Document.parse("{ total : { $multiply: [ {$add : [\"$netPrice\", \"$tax\"]}, 5] } }")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1552
|
||||
*/
|
||||
@Test
|
||||
public void shouldExposeDefaultCountField() {
|
||||
|
||||
BucketOperation operation = bucket("field");
|
||||
|
||||
assertThat(operation.getFields().exposesSingleFieldOnly(), is(true));
|
||||
assertThat(operation.getFields().getField("count"), is(notNullValue()));
|
||||
}
|
||||
|
||||
private static Document extractOutput(Document fromBucketClause) {
|
||||
return (Document) ((Document) fromBucketClause.get("$bucket")).get("output");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user