Skip to content

Commit c7558f9

Browse files
authored
Add builders for percentile and median accumulators/window functions (#1139)
JAVA-3860
1 parent 29455c6 commit c7558f9

File tree

13 files changed

+661
-7
lines changed

13 files changed

+661
-7
lines changed

driver-core/src/main/com/mongodb/client/model/Accumulators.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,51 @@ public static <TExpression> BsonField avg(final String fieldName, final TExpress
6767
return accumulatorOperator("$avg", fieldName, expression);
6868
}
6969

70+
/**
71+
* Returns a combination of a computed field and an accumulator that generates a BSON {@link org.bson.BsonType#ARRAY Array}
72+
* containing computed values from the given {@code inExpression} based on the provided {@code pExpression}, which represents an array
73+
* of percentiles of interest within a group, where each element is a numeric value between 0.0 and 1.0 (inclusive).
74+
*
75+
* @param fieldName The field computed by the accumulator.
76+
* @param inExpression The input expression.
77+
* @param pExpression The expression representing a percentiles of interest.
78+
* @param method The method to be used for computing the percentiles.
79+
* @param <InExpression> The type of the input expression.
80+
* @param <PExpression> The type of the percentile expression.
81+
* @return The requested {@link BsonField}.
82+
* @mongodb.driver.manual reference/operator/aggregation/percentile/ $percentile
83+
* @since 4.10
84+
* @mongodb.server.release 7.0
85+
*/
86+
public static <InExpression, PExpression> BsonField percentile(final String fieldName, final InExpression inExpression,
87+
final PExpression pExpression, final QuantileMethod method) {
88+
notNull("fieldName", fieldName);
89+
notNull("inExpression", inExpression);
90+
notNull("pExpression", inExpression);
91+
notNull("method", method);
92+
return quantileAccumulator("$percentile", fieldName, inExpression, pExpression, method);
93+
}
94+
95+
/**
96+
* Returns a combination of a computed field and an accumulator that generates a BSON {@link org.bson.BsonType#DOUBLE Double }
97+
* representing the median value computed from the given {@code inExpression} within a group.
98+
*
99+
* @param fieldName The field computed by the accumulator.
100+
* @param inExpression The input expression.
101+
* @param method The method to be used for computing the median.
102+
* @param <InExpression> The type of the input expression.
103+
* @return The requested {@link BsonField}.
104+
* @mongodb.driver.manual reference/operator/aggregation/median/ $median
105+
* @since 4.10
106+
* @mongodb.server.release 7.0
107+
*/
108+
public static <InExpression> BsonField median(final String fieldName, final InExpression inExpression, final QuantileMethod method) {
109+
notNull("fieldName", fieldName);
110+
notNull("inExpression", inExpression);
111+
notNull("method", method);
112+
return quantileAccumulator("$median", fieldName, inExpression, null, method);
113+
}
114+
70115
/**
71116
* Gets a field name for a $group operation representing the value of the given expression when applied to the first member of
72117
* the group.
@@ -510,6 +555,17 @@ private static <OutExpression, NExpression> BsonField sortingPickNAccumulator(
510555
.append("n", nExpression)));
511556
}
512557

558+
private static <InExpression, PExpression> BsonField quantileAccumulator(final String quantileAccumulatorName,
559+
final String fieldName, final InExpression inExpression,
560+
@Nullable final PExpression pExpression, final QuantileMethod method) {
561+
Document document = new Document("input", inExpression)
562+
.append("method", method.toBsonValue());
563+
if (pExpression != null) {
564+
document.append("p", pExpression);
565+
}
566+
return accumulatorOperator(quantileAccumulatorName, fieldName, document);
567+
}
568+
513569
private Accumulators() {
514570
}
515571
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
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 com.mongodb.client.model;
17+
18+
import com.mongodb.annotations.Sealed;
19+
20+
21+
/**
22+
* @see QuantileMethod#approximate()
23+
* @since 4.10
24+
* @mongodb.server.release 7.0
25+
*/
26+
@Sealed
27+
public interface ApproximateQuantileMethod extends QuantileMethod {
28+
}
29+
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
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 com.mongodb.client.model;
17+
18+
import com.mongodb.annotations.Sealed;
19+
import org.bson.BsonString;
20+
import org.bson.BsonValue;
21+
22+
import static com.mongodb.assertions.Assertions.notNull;
23+
24+
/**
25+
* This interface represents a quantile method used in quantile accumulators of the {@code $group} and
26+
* {@code $setWindowFields} stages.
27+
* <p>
28+
* It provides methods for creating and converting quantile methods to {@link BsonValue}.
29+
* </p>
30+
*
31+
* @see Accumulators#percentile(String, Object, Object, QuantileMethod)
32+
* @see Accumulators#median(String, Object, QuantileMethod)
33+
* @see WindowOutputFields#percentile(String, Object, Object, QuantileMethod, Window)
34+
* @see WindowOutputFields#median(String, Object, QuantileMethod, Window)
35+
* @since 4.10
36+
* @mongodb.server.release 7.0
37+
*/
38+
@Sealed
39+
public interface QuantileMethod {
40+
/**
41+
* Returns a {@link QuantileMethod} instance representing the "approximate" quantile method.
42+
*
43+
* @return The requested {@link QuantileMethod}.
44+
*/
45+
static ApproximateQuantileMethod approximate() {
46+
return new QuantileMethodBson(new BsonString("approximate"));
47+
}
48+
49+
/**
50+
* Creates a {@link QuantileMethod} from a {@link BsonValue} in situations when there is no builder method
51+
* that better satisfies your needs.
52+
* This method cannot be used to validate the syntax.
53+
* <p>
54+
* <i>Example</i><br>
55+
* The following code creates two functionally equivalent {@link QuantileMethod}s,
56+
* though they may not be {@linkplain Object#equals(Object) equal}.
57+
* <pre>{@code
58+
* QuantileMethod method1 = QuantileMethod.approximate();
59+
* QuantileMethod method2 = QuantileMethod.of(new BsonString("approximate"));
60+
* }</pre>
61+
*
62+
* @param method A {@link BsonValue} representing the required {@link QuantileMethod}.
63+
* @return The requested {@link QuantileMethod}.
64+
*/
65+
static QuantileMethod of(final BsonValue method) {
66+
notNull("method", method);
67+
return new QuantileMethodBson(method);
68+
}
69+
70+
/**
71+
* Converts this object to {@link BsonValue}.
72+
*
73+
* @return A {@link BsonValue} representing this {@link QuantileMethod}.
74+
*/
75+
BsonValue toBsonValue();
76+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
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 com.mongodb.client.model;
17+
18+
import org.bson.BsonValue;
19+
20+
import java.util.Objects;
21+
22+
final class QuantileMethodBson implements ApproximateQuantileMethod {
23+
private final BsonValue bsonValue;
24+
25+
QuantileMethodBson(final BsonValue bsonValue) {
26+
this.bsonValue = bsonValue;
27+
}
28+
29+
@Override
30+
public BsonValue toBsonValue() {
31+
return bsonValue;
32+
}
33+
34+
@Override
35+
public boolean equals(final Object o) {
36+
if (this == o) {
37+
return true;
38+
}
39+
if (o == null || getClass() != o.getClass()) {
40+
return false;
41+
}
42+
QuantileMethodBson that = (QuantileMethodBson) o;
43+
return Objects.equals(bsonValue, that.bsonValue);
44+
}
45+
46+
@Override
47+
public int hashCode() {
48+
return Objects.hash(bsonValue);
49+
}
50+
}

driver-core/src/main/com/mongodb/client/model/WindowOutputFields.java

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,62 @@ public static <TExpression> WindowOutputField avg(final String path, final TExpr
111111
return simpleParameterWindowFunction(path, "$avg", expression, window);
112112
}
113113

114+
/**
115+
* Builds a window output field of percentiles of the evaluation results of the {@code inExpression}
116+
* over documents in the specified {@code window}. The {@code pExpression} parameter represents an array of
117+
* percentiles of interest, with each element being a numeric value between 0.0 and 1.0 (inclusive).
118+
*
119+
* @param path The output field path.
120+
* @param inExpression The input expression.
121+
* @param pExpression The expression representing a percentiles of interest.
122+
* @param method The method to be used for computing the percentiles.
123+
* @param window The window.
124+
* @param <InExpression> The type of the input expression.
125+
* @param <PExpression> The type of the percentile expression.
126+
* @return The constructed windowed output field.
127+
* @mongodb.driver.manual reference/operator/aggregation/percentile/ $percentile
128+
* @since 4.10
129+
* @mongodb.server.release 7.0
130+
*/
131+
public static <InExpression, PExpression> WindowOutputField percentile(final String path, final InExpression inExpression,
132+
final PExpression pExpression, final QuantileMethod method,
133+
@Nullable final Window window) {
134+
notNull("path", path);
135+
notNull("inExpression", inExpression);
136+
notNull("pExpression", pExpression);
137+
notNull("method", method);
138+
Map<ParamName, Object> args = new LinkedHashMap<>(3);
139+
args.put(ParamName.INPUT, inExpression);
140+
args.put(ParamName.P_LOWERCASE, pExpression);
141+
args.put(ParamName.METHOD, method.toBsonValue());
142+
return compoundParameterWindowFunction(path, "$percentile", args, window);
143+
}
144+
145+
/**
146+
* Builds a window output field representing the median value of the evaluation results of the {@code inExpression}
147+
* over documents in the specified {@code window}.
148+
*
149+
* @param inExpression The input expression.
150+
* @param method The method to be used for computing the median.
151+
* @param window The window.
152+
* @param <InExpression> The type of the input expression.
153+
* @return The constructed windowed output field.
154+
* @mongodb.driver.manual reference/operator/aggregation/median/ $median
155+
* @since 4.10
156+
* @mongodb.server.release 7.0
157+
*/
158+
public static <InExpression> WindowOutputField median(final String path, final InExpression inExpression,
159+
final QuantileMethod method,
160+
@Nullable final Window window) {
161+
notNull("path", path);
162+
notNull("inExpression", inExpression);
163+
notNull("method", method);
164+
Map<ParamName, Object> args = new LinkedHashMap<>(2);
165+
args.put(ParamName.INPUT, inExpression);
166+
args.put(ParamName.METHOD, method.toBsonValue());
167+
return compoundParameterWindowFunction(path, "$median", args, window);
168+
}
169+
114170
/**
115171
* Builds a window output field of the sample standard deviation of the evaluation results of the {@code expression} over the
116172
* {@code window}.
@@ -1013,11 +1069,13 @@ private enum ParamName {
10131069
UNIT("unit"),
10141070
N_UPPERCASE("N"),
10151071
N_LOWERCASE("n"),
1072+
P_LOWERCASE("p"),
10161073
ALPHA("alpha"),
10171074
OUTPUT("output"),
10181075
BY("by"),
10191076
DEFAULT("default"),
1020-
SORT_BY("sortBy");
1077+
SORT_BY("sortBy"),
1078+
METHOD("method");
10211079

10221080
private final String value;
10231081

0 commit comments

Comments
 (0)