Skip to content

Commit bd9765a

Browse files
authored
Add $unset and $geoNear stages (#998)
JAVA-4594
1 parent 383b47c commit bd9765a

File tree

11 files changed

+656
-2
lines changed

11 files changed

+656
-2
lines changed

config/checkstyle/suppressions.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
<!--DBCollection is insanely long, and we should not compromise every class length for this one-->
7979
<suppress checks="FileLength" files="DBCollection"/>
8080
<suppress checks="FileLength" files="MongoCollection"/>
81+
<suppress checks="FileLength" files="Aggregates"/>
8182

8283
<suppress checks="ParameterNumber" files="Connection"/>
8384
<suppress checks="ParameterNumber" files="DefaultServer"/>

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

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121
import com.mongodb.client.model.densify.DensifyRange;
2222
import com.mongodb.client.model.fill.FillOutputField;
2323
import com.mongodb.client.model.fill.FillOptions;
24+
import com.mongodb.client.model.geojson.Point;
2425
import com.mongodb.client.model.search.SearchOperator;
2526
import com.mongodb.client.model.search.SearchCollector;
2627
import com.mongodb.client.model.search.SearchOptions;
2728
import com.mongodb.lang.Nullable;
29+
import org.bson.BsonArray;
2830
import org.bson.BsonBoolean;
2931
import org.bson.BsonDocument;
3032
import org.bson.BsonDocumentWriter;
@@ -35,11 +37,13 @@
3537
import org.bson.codecs.configuration.CodecRegistry;
3638
import org.bson.conversions.Bson;
3739

40+
import java.util.Arrays;
3841
import java.util.List;
3942
import java.util.Map;
4043
import java.util.Objects;
4144

4245
import static com.mongodb.assertions.Assertions.assertTrue;
46+
import static com.mongodb.client.model.GeoNearOptions.geoNearOptions;
4347
import static com.mongodb.client.model.densify.DensifyOptions.densifyOptions;
4448
import static com.mongodb.assertions.Assertions.isTrueArgument;
4549
import static com.mongodb.assertions.Assertions.notNull;
@@ -920,6 +924,104 @@ public static Bson searchMeta(final SearchCollector collector, final SearchOptio
920924
return new SearchStage("$searchMeta", notNull("collector", collector), notNull("options", options));
921925
}
922926

927+
/**
928+
* Creates an $unset pipeline stage that removes/excludes fields from documents
929+
*
930+
* @param fields the fields to exclude. May use dot notation.
931+
* @return the $unset pipeline stage
932+
* @mongodb.driver.manual reference/operator/aggregation/project/ $unset
933+
* @mongodb.server.release 4.2
934+
* @since 4.8
935+
*/
936+
public static Bson unset(final String... fields) {
937+
return unset(Arrays.asList(fields));
938+
}
939+
940+
/**
941+
* Creates an $unset pipeline stage that removes/excludes fields from documents
942+
*
943+
* @param fields the fields to exclude. May use dot notation.
944+
* @return the $unset pipeline stage
945+
* @mongodb.driver.manual reference/operator/aggregation/project/ $unset
946+
* @mongodb.server.release 4.2
947+
* @since 4.8
948+
*/
949+
public static Bson unset(final List<String> fields) {
950+
if (fields.size() == 1) {
951+
return new BsonDocument("$unset", new BsonString(fields.get(0)));
952+
}
953+
BsonArray array = new BsonArray();
954+
fields.stream().map(BsonString::new).forEach(array::add);
955+
return new BsonDocument().append("$unset", array);
956+
}
957+
958+
/**
959+
* Creates a $geoNear pipeline stage that outputs documents in order of nearest to farthest from a specified point.
960+
*
961+
* @param near The point for which to find the closest documents.
962+
* @param distanceField The output field that contains the calculated distance.
963+
* To specify a field within an embedded document, use dot notation.
964+
* @param options {@link GeoNearOptions}
965+
* @return the $geoNear pipeline stage
966+
* @mongodb.driver.manual reference/operator/aggregation/project/ $geoNear
967+
* @since 4.8
968+
*/
969+
public static Bson geoNear(
970+
final Point near,
971+
final String distanceField,
972+
final GeoNearOptions options) {
973+
notNull("near", near);
974+
notNull("distanceField", distanceField);
975+
notNull("options", options);
976+
return new Bson() {
977+
@Override
978+
public <TDocument> BsonDocument toBsonDocument(final Class<TDocument> documentClass, final CodecRegistry codecRegistry) {
979+
BsonDocumentWriter writer = new BsonDocumentWriter(new BsonDocument());
980+
writer.writeStartDocument();
981+
writer.writeStartDocument("$geoNear");
982+
983+
writer.writeName("near");
984+
BuildersHelper.encodeValue(writer, near, codecRegistry);
985+
writer.writeName("distanceField");
986+
BuildersHelper.encodeValue(writer, distanceField, codecRegistry);
987+
988+
options.toBsonDocument(documentClass, codecRegistry).forEach((optionName, optionValue) -> {
989+
writer.writeName(optionName);
990+
BuildersHelper.encodeValue(writer, optionValue, codecRegistry);
991+
});
992+
993+
writer.writeEndDocument();
994+
writer.writeEndDocument();
995+
return writer.getDocument();
996+
}
997+
998+
@Override
999+
public String toString() {
1000+
return "Stage{name='$geoNear'"
1001+
+ ", near=" + near
1002+
+ ", distanceField=" + distanceField
1003+
+ ", options=" + options
1004+
+ '}';
1005+
}
1006+
};
1007+
}
1008+
1009+
/**
1010+
* Creates a $geoNear pipeline stage that outputs documents in order of nearest to farthest from a specified point.
1011+
*
1012+
* @param near The point for which to find the closest documents.
1013+
* @param distanceField The output field that contains the calculated distance.
1014+
* To specify a field within an embedded document, use dot notation.
1015+
* @return the $geoNear pipeline stage
1016+
* @mongodb.driver.manual reference/operator/aggregation/project/ $geoNear
1017+
* @since 4.8
1018+
*/
1019+
public static Bson geoNear(
1020+
final Point near,
1021+
final String distanceField) {
1022+
return geoNear(near, distanceField, geoNearOptions());
1023+
}
1024+
9231025
static void writeBucketOutput(final CodecRegistry codecRegistry, final BsonDocumentWriter writer,
9241026
@Nullable final List<BsonField> output) {
9251027
if (output != null) {
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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+
17+
package com.mongodb.client.model;
18+
19+
import com.mongodb.annotations.Immutable;
20+
import com.mongodb.internal.client.model.AbstractConstructibleBson;
21+
import org.bson.BsonDocument;
22+
import org.bson.Document;
23+
import org.bson.conversions.Bson;
24+
25+
final class GeoNearConstructibleBson extends AbstractConstructibleBson<GeoNearConstructibleBson> implements GeoNearOptions {
26+
/**
27+
* An {@linkplain Immutable immutable} {@link BsonDocument#isEmpty() empty} instance.
28+
*/
29+
static final GeoNearOptions EMPTY_IMMUTABLE = new GeoNearConstructibleBson(AbstractConstructibleBson.EMPTY_IMMUTABLE);
30+
31+
private GeoNearConstructibleBson(final Bson base) {
32+
super(base);
33+
}
34+
35+
private GeoNearConstructibleBson(final Bson base, final Document appended) {
36+
super(base, appended);
37+
}
38+
39+
private GeoNearOptions setOption(final String key, final Object value) {
40+
return newAppended(key, value);
41+
}
42+
43+
@Override
44+
public GeoNearOptions distanceMultiplier(final Number distanceMultiplier) {
45+
return setOption("distanceMultiplier", distanceMultiplier);
46+
}
47+
48+
@Override
49+
public GeoNearOptions includeLocs(final String includeLocs) {
50+
return setOption("includeLocs", includeLocs);
51+
}
52+
53+
@Override
54+
public GeoNearOptions key(final String key) {
55+
return setOption("key", key);
56+
}
57+
58+
@Override
59+
public GeoNearOptions minDistance(final Number minDistance) {
60+
return setOption("minDistance", minDistance);
61+
}
62+
63+
@Override
64+
public GeoNearOptions maxDistance(final Number maxDistance) {
65+
return setOption("maxDistance", maxDistance);
66+
}
67+
68+
@Override
69+
public GeoNearOptions query(final Document query) {
70+
return setOption("query", query);
71+
}
72+
73+
@Override
74+
public GeoNearOptions spherical() {
75+
return setOption("spherical", true);
76+
}
77+
78+
@Override
79+
protected GeoNearConstructibleBson newSelf(final Bson base, final Document appended) {
80+
return new GeoNearConstructibleBson(base, appended);
81+
}
82+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
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+
17+
package com.mongodb.client.model;
18+
19+
import org.bson.Document;
20+
import org.bson.conversions.Bson;
21+
22+
/**
23+
* The options for a {@link Aggregates#geoNear} pipeline stage.
24+
*
25+
* @mongodb.driver.manual reference/operator/aggregation/unwind/ $geoNear
26+
* @since 4.8
27+
*/
28+
public interface GeoNearOptions extends Bson {
29+
/**
30+
* Returns {@link GeoNearOptions} that represents server defaults.
31+
*
32+
* @return {@link GeoNearOptions} that represents server defaults.
33+
*/
34+
static GeoNearOptions geoNearOptions() {
35+
return GeoNearConstructibleBson.EMPTY_IMMUTABLE;
36+
}
37+
38+
/**
39+
* @param distanceMultiplier The factor to multiply all distances returned by the query.
40+
* @return a new {@link GeoNearOptions} with the provided option set
41+
* @since 4.8
42+
*/
43+
GeoNearOptions distanceMultiplier(Number distanceMultiplier);
44+
45+
/**
46+
* This specifies the output field that identifies the location used to calculate the distance.
47+
* This option is useful when a location field contains multiple locations.
48+
* To specify a field within an embedded document, use dot notation.
49+
*
50+
* @param includeLocs the output field
51+
* @return a new {@link GeoNearOptions} with the provided option set
52+
* @since 4.8
53+
*/
54+
GeoNearOptions includeLocs(String includeLocs);
55+
56+
/**
57+
* Specify the geospatial indexed field to use when calculating the distance.
58+
*
59+
* @param key the geospatial indexed field.
60+
* @return a new {@link GeoNearOptions} with the provided option set
61+
* @since 4.8
62+
*/
63+
GeoNearOptions key(String key);
64+
65+
/**
66+
* The minimum distance from the center point that the documents can be.
67+
* MongoDB limits the results to those documents that fall outside the specified distance from the center point.
68+
*
69+
* @param minDistance the distance in meters for GeoJSON data.
70+
* @return a new {@link GeoNearOptions} with the provided option set
71+
* @since 4.8
72+
*/
73+
GeoNearOptions minDistance(Number minDistance);
74+
75+
/**
76+
* The maximum distance from the center point that the documents can be.
77+
* MongoDB limits the results to those documents that fall within the specified distance from the center point.
78+
*
79+
* @param maxDistance the distance in meters for GeoJSON data.
80+
* @return a new {@link GeoNearOptions} with the provided option set
81+
* @since 4.8
82+
*/
83+
GeoNearOptions maxDistance(Number maxDistance);
84+
85+
/**
86+
* Limits the results to the documents that match the query.
87+
* The query syntax is the usual MongoDB read operation query syntax.
88+
*
89+
* @param query the query
90+
* @return a new {@link GeoNearOptions} with the provided option set
91+
* @since 4.8
92+
*/
93+
GeoNearOptions query(Document query);
94+
95+
/**
96+
* Determines how MongoDB calculates the distance between two points.
97+
* By default, when this option is not provided, MongoDB uses $near semantics:
98+
* spherical geometry for 2dsphere indexes and planar geometry for 2d indexes.
99+
* When provided, MongoDB uses $nearSphere semantics and calculates distances
100+
* using spherical geometry.
101+
*
102+
* @return a new {@link GeoNearOptions} with the provided option set
103+
* @since 4.8
104+
*/
105+
GeoNearOptions spherical();
106+
}

driver-core/src/test/functional/com/mongodb/OperationFunctionalSpecification.groovy

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,19 @@ import static com.mongodb.internal.operation.OperationUnitSpecification.getMaxWi
7676
class OperationFunctionalSpecification extends Specification {
7777

7878
def setup() {
79+
setupInternal()
80+
}
81+
82+
protected void setupInternal() {
7983
ServerHelper.checkPool(getPrimary())
8084
CollectionHelper.drop(getNamespace())
8185
}
8286

83-
def cleanup() {
87+
void cleanup() {
88+
cleanupInternal()
89+
}
90+
91+
protected void cleanupInternal() {
8492
CollectionHelper.drop(getNamespace())
8593
checkReferenceCountReachesTarget(getBinding(), 1)
8694
checkReferenceCountReachesTarget(getAsyncBinding(), 1)

0 commit comments

Comments
 (0)