Skip to content

Commit 4505491

Browse files
mp911dechristophstrobl
authored andcommitted
DATAMONGO-1552 - Add $facet aggregation stage.
Original Pull Request: #426
1 parent b7a0b1d commit 4505491

File tree

6 files changed

+543
-59
lines changed

6 files changed

+543
-59
lines changed

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

Lines changed: 24 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.springframework.data.mongodb.core.aggregation.ExposedFields.DirectFieldReference;
2929
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
3030
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
31+
import org.springframework.data.mongodb.core.aggregation.FacetOperation.FacetOperationBuilder;
3132
import org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation.InheritsFieldsAggregationOperation;
3233
import org.springframework.data.mongodb.core.aggregation.GraphLookupOperation.StartWithBuilder;
3334
import org.springframework.data.mongodb.core.aggregation.ReplaceRootOperation.ReplaceRootDocumentOperationBuilder;
@@ -66,7 +67,7 @@ public class Aggregation {
6667
*/
6768
public static final String CURRENT = SystemVariable.CURRENT.toString();
6869

69-
public static final AggregationOperationContext DEFAULT_CONTEXT = new NoOpAggregationOperationContext();
70+
public static final AggregationOperationContext DEFAULT_CONTEXT = AggregationOperationRenderer.DEFAULT_CONTEXT;
7071
public static final AggregationOptions DEFAULT_OPTIONS = newAggregationOptions().build();
7172

7273
protected final List<AggregationOperation> operations;
@@ -458,6 +459,25 @@ public static BucketAutoOperation bucketAuto(AggregationExpression groupByExpres
458459
return new BucketAutoOperation(groupByExpression, buckets);
459460
}
460461

462+
/**
463+
* Creates a new {@link FacetOperation}.
464+
*
465+
* @return
466+
*/
467+
public static FacetOperation facet() {
468+
return FacetOperation.EMPTY;
469+
}
470+
471+
/**
472+
* Creates a new {@link FacetOperationBuilder} given {@link Aggregation}.
473+
*
474+
* @param aggregationOperations the sub-pipeline, must not be {@literal null}.
475+
* @return
476+
*/
477+
public static FacetOperationBuilder facet(AggregationOperation... aggregationOperations) {
478+
return facet().and(aggregationOperations);
479+
}
480+
461481
/**
462482
* Creates a new {@link LookupOperation}.
463483
*
@@ -549,26 +569,7 @@ public static AggregationOptions.Builder newAggregationOptions() {
549569
*/
550570
public Document toDocument(String inputCollectionName, AggregationOperationContext rootContext) {
551571

552-
AggregationOperationContext context = rootContext;
553-
List<Document> operationDocuments = new ArrayList<Document>(operations.size());
554-
555-
for (AggregationOperation operation : operations) {
556-
557-
operationDocuments.add(operation.toDocument(context));
558-
559-
if (operation instanceof FieldsExposingAggregationOperation) {
560-
561-
FieldsExposingAggregationOperation exposedFieldsOperation = (FieldsExposingAggregationOperation) operation;
562-
ExposedFields fields = exposedFieldsOperation.getFields();
563-
564-
if (operation instanceof InheritsFieldsAggregationOperation) {
565-
context = new InheritingExposedFieldsAggregationOperationContext(fields, context);
566-
} else {
567-
context = fields.exposesNoFields() ? DEFAULT_CONTEXT
568-
: new ExposedFieldsAggregationOperationContext(fields, context);
569-
}
570-
}
571-
}
572+
List<Document> operationDocuments = AggregationOperationRenderer.toDocument(operations, rootContext);
572573

573574
Document command = new Document("aggregate", inputCollectionName);
574575
command.put("pipeline", operationDocuments);
@@ -584,43 +585,7 @@ public Document toDocument(String inputCollectionName, AggregationOperationConte
584585
*/
585586
@Override
586587
public String toString() {
587-
return SerializationUtils
588-
.serializeToJsonSafely(toDocument("__collection__", new NoOpAggregationOperationContext()));
589-
}
590-
591-
/**
592-
* Simple {@link AggregationOperationContext} that just returns {@link FieldReference}s as is.
593-
*
594-
* @author Oliver Gierke
595-
*/
596-
private static class NoOpAggregationOperationContext implements AggregationOperationContext {
597-
598-
/*
599-
* (non-Javadoc)
600-
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getMappedObject(com.mongodb.Document)
601-
*/
602-
@Override
603-
public Document getMappedObject(Document document) {
604-
return document;
605-
}
606-
607-
/*
608-
* (non-Javadoc)
609-
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getReference(org.springframework.data.mongodb.core.aggregation.ExposedFields.AvailableField)
610-
*/
611-
@Override
612-
public FieldReference getReference(Field field) {
613-
return new DirectFieldReference(new ExposedField(field, true));
614-
}
615-
616-
/*
617-
* (non-Javadoc)
618-
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getReference(java.lang.String)
619-
*/
620-
@Override
621-
public FieldReference getReference(String name) {
622-
return new DirectFieldReference(new ExposedField(new AggregationField(name), true));
623-
}
588+
return SerializationUtils.serializeToJsonSafely(toDocument("__collection__", DEFAULT_CONTEXT));
624589
}
625590

626591
/**
@@ -660,7 +625,7 @@ public static boolean isReferingToSystemVariable(String fieldRef) {
660625
return false;
661626
}
662627

663-
/*
628+
/*
664629
* (non-Javadoc)
665630
* @see java.lang.Enum#toString()
666631
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
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.List;
20+
21+
import org.bson.Document;
22+
import org.springframework.data.mongodb.core.aggregation.ExposedFields.DirectFieldReference;
23+
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
24+
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
25+
import org.springframework.data.mongodb.core.aggregation.Fields.AggregationField;
26+
import org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation.InheritsFieldsAggregationOperation;
27+
28+
/**
29+
* Rendering support for {@link AggregationOperation} into a {@link List} of {@link com.mongodb.Document}.
30+
*
31+
* @author Mark Paluch
32+
* @author Christoph Strobl
33+
* @since 1.10
34+
*/
35+
class AggregationOperationRenderer {
36+
37+
static final AggregationOperationContext DEFAULT_CONTEXT = new NoOpAggregationOperationContext();
38+
39+
/**
40+
* Render a {@link List} of {@link AggregationOperation} given {@link AggregationOperationContext} into their
41+
* {@link Document} representation.
42+
*
43+
* @param operations must not be {@literal null}.
44+
* @param context must not be {@literal null}.
45+
* @return the {@link List} of {@link Document}.
46+
*/
47+
static List<Document> toDocument(List<AggregationOperation> operations, AggregationOperationContext rootContext) {
48+
49+
List<Document> operationDocuments = new ArrayList<Document>(operations.size());
50+
51+
AggregationOperationContext contextToUse = rootContext;
52+
53+
for (AggregationOperation operation : operations) {
54+
55+
operationDocuments.add(operation.toDocument(contextToUse));
56+
57+
if (operation instanceof FieldsExposingAggregationOperation) {
58+
59+
FieldsExposingAggregationOperation exposedFieldsOperation = (FieldsExposingAggregationOperation) operation;
60+
ExposedFields fields = exposedFieldsOperation.getFields();
61+
62+
if (operation instanceof InheritsFieldsAggregationOperation) {
63+
contextToUse = new InheritingExposedFieldsAggregationOperationContext(fields, contextToUse);
64+
} else {
65+
contextToUse = fields.exposesNoFields() ? DEFAULT_CONTEXT
66+
: new ExposedFieldsAggregationOperationContext(exposedFieldsOperation.getFields(), contextToUse);
67+
}
68+
}
69+
}
70+
71+
return operationDocuments;
72+
}
73+
74+
/**
75+
* Simple {@link AggregationOperationContext} that just returns {@link FieldReference}s as is.
76+
*
77+
* @author Oliver Gierke
78+
*/
79+
private static class NoOpAggregationOperationContext implements AggregationOperationContext {
80+
81+
/*
82+
* (non-Javadoc)
83+
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getMappedObject(org.bson.Document)
84+
*/
85+
@Override
86+
public Document getMappedObject(Document document) {
87+
return document;
88+
}
89+
90+
/*
91+
* (non-Javadoc)
92+
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getReference(org.springframework.data.mongodb.core.aggregation.ExposedFields.AvailableField)
93+
*/
94+
@Override
95+
public FieldReference getReference(Field field) {
96+
return new DirectFieldReference(new ExposedField(field, true));
97+
}
98+
99+
/*
100+
* (non-Javadoc)
101+
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getReference(java.lang.String)
102+
*/
103+
@Override
104+
public FieldReference getReference(String name) {
105+
return new DirectFieldReference(new ExposedField(new AggregationField(name), true));
106+
}
107+
}
108+
}

0 commit comments

Comments
 (0)