Skip to content

Add $unset and $geoNear stages #998

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Sep 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/checkstyle/suppressions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
<!--DBCollection is insanely long, and we should not compromise every class length for this one-->
<suppress checks="FileLength" files="DBCollection"/>
<suppress checks="FileLength" files="MongoCollection"/>
<suppress checks="FileLength" files="Aggregates"/>

<suppress checks="ParameterNumber" files="Connection"/>
<suppress checks="ParameterNumber" files="DefaultServer"/>
Expand Down
102 changes: 102 additions & 0 deletions driver-core/src/main/com/mongodb/client/model/Aggregates.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
import com.mongodb.client.model.densify.DensifyRange;
import com.mongodb.client.model.fill.FillOutputField;
import com.mongodb.client.model.fill.FillOptions;
import com.mongodb.client.model.geojson.Point;
import com.mongodb.client.model.search.SearchOperator;
import com.mongodb.client.model.search.SearchCollector;
import com.mongodb.client.model.search.SearchOptions;
import com.mongodb.lang.Nullable;
import org.bson.BsonArray;
import org.bson.BsonBoolean;
import org.bson.BsonDocument;
import org.bson.BsonDocumentWriter;
Expand All @@ -35,11 +37,13 @@
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.conversions.Bson;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static com.mongodb.assertions.Assertions.assertTrue;
import static com.mongodb.client.model.GeoNearOptions.geoNearOptions;
import static com.mongodb.client.model.densify.DensifyOptions.densifyOptions;
import static com.mongodb.assertions.Assertions.isTrueArgument;
import static com.mongodb.assertions.Assertions.notNull;
Expand Down Expand Up @@ -920,6 +924,104 @@ public static Bson searchMeta(final SearchCollector collector, final SearchOptio
return new SearchStage("$searchMeta", notNull("collector", collector), notNull("options", options));
}

/**
* Creates an $unset pipeline stage that removes/excludes fields from documents
*
* @param fields the fields to exclude. May use dot notation.
* @return the $unset pipeline stage
* @mongodb.driver.manual reference/operator/aggregation/project/ $unset
* @mongodb.server.release 4.2
* @since 4.8
*/
public static Bson unset(final String... fields) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a public static Bson unset(final List<String> fields) version as well - this keeps it inline with other helpers.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

return unset(Arrays.asList(fields));
}

/**
* Creates an $unset pipeline stage that removes/excludes fields from documents
*
* @param fields the fields to exclude. May use dot notation.
* @return the $unset pipeline stage
* @mongodb.driver.manual reference/operator/aggregation/project/ $unset
* @mongodb.server.release 4.2
* @since 4.8
*/
public static Bson unset(final List<String> fields) {
if (fields.size() == 1) {
return new BsonDocument("$unset", new BsonString(fields.get(0)));
}
BsonArray array = new BsonArray();
fields.stream().map(BsonString::new).forEach(array::add);
return new BsonDocument().append("$unset", array);
}

/**
* Creates a $geoNear pipeline stage that outputs documents in order of nearest to farthest from a specified point.
*
* @param near The point for which to find the closest documents.
* @param distanceField The output field that contains the calculated distance.
* To specify a field within an embedded document, use dot notation.
* @param options {@link GeoNearOptions}
* @return the $geoNear pipeline stage
* @mongodb.driver.manual reference/operator/aggregation/project/ $geoNear
* @since 4.8
*/
public static Bson geoNear(
final Point near,
final String distanceField,
final GeoNearOptions options) {
notNull("near", near);
notNull("distanceField", distanceField);
notNull("options", options);
return new Bson() {
@Override
public <TDocument> BsonDocument toBsonDocument(final Class<TDocument> documentClass, final CodecRegistry codecRegistry) {
BsonDocumentWriter writer = new BsonDocumentWriter(new BsonDocument());
writer.writeStartDocument();
writer.writeStartDocument("$geoNear");

writer.writeName("near");
BuildersHelper.encodeValue(writer, near, codecRegistry);
writer.writeName("distanceField");
BuildersHelper.encodeValue(writer, distanceField, codecRegistry);

options.toBsonDocument(documentClass, codecRegistry).forEach((optionName, optionValue) -> {
writer.writeName(optionName);
BuildersHelper.encodeValue(writer, optionValue, codecRegistry);
});

writer.writeEndDocument();
writer.writeEndDocument();
return writer.getDocument();
}

@Override
public String toString() {
return "Stage{name='$geoNear'"
+ ", near=" + near
+ ", distanceField=" + distanceField
+ ", options=" + options
+ '}';
}
};
}

/**
* Creates a $geoNear pipeline stage that outputs documents in order of nearest to farthest from a specified point.
*
* @param near The point for which to find the closest documents.
* @param distanceField The output field that contains the calculated distance.
* To specify a field within an embedded document, use dot notation.
* @return the $geoNear pipeline stage
* @mongodb.driver.manual reference/operator/aggregation/project/ $geoNear
* @since 4.8
*/
public static Bson geoNear(
final Point near,
final String distanceField) {
return geoNear(near, distanceField, geoNearOptions());
}

static void writeBucketOutput(final CodecRegistry codecRegistry, final BsonDocumentWriter writer,
@Nullable final List<BsonField> output) {
if (output != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright 2008-present MongoDB, Inc.
*
* 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 com.mongodb.client.model;

import com.mongodb.annotations.Immutable;
import com.mongodb.internal.client.model.AbstractConstructibleBson;
import org.bson.BsonDocument;
import org.bson.Document;
import org.bson.conversions.Bson;

final class GeoNearConstructibleBson extends AbstractConstructibleBson<GeoNearConstructibleBson> implements GeoNearOptions {
/**
* An {@linkplain Immutable immutable} {@link BsonDocument#isEmpty() empty} instance.
*/
static final GeoNearOptions EMPTY_IMMUTABLE = new GeoNearConstructibleBson(AbstractConstructibleBson.EMPTY_IMMUTABLE);

private GeoNearConstructibleBson(final Bson base) {
super(base);
}

private GeoNearConstructibleBson(final Bson base, final Document appended) {
super(base, appended);
}

private GeoNearOptions setOption(final String key, final Object value) {
return newAppended(key, value);
}

@Override
public GeoNearOptions distanceMultiplier(final Number distanceMultiplier) {
return setOption("distanceMultiplier", distanceMultiplier);
}

@Override
public GeoNearOptions includeLocs(final String includeLocs) {
return setOption("includeLocs", includeLocs);
}

@Override
public GeoNearOptions key(final String key) {
return setOption("key", key);
}

@Override
public GeoNearOptions minDistance(final Number minDistance) {
return setOption("minDistance", minDistance);
}

@Override
public GeoNearOptions maxDistance(final Number maxDistance) {
return setOption("maxDistance", maxDistance);
}

@Override
public GeoNearOptions query(final Document query) {
return setOption("query", query);
}

@Override
public GeoNearOptions spherical() {
return setOption("spherical", true);
}

@Override
protected GeoNearConstructibleBson newSelf(final Bson base, final Document appended) {
return new GeoNearConstructibleBson(base, appended);
}
}
106 changes: 106 additions & 0 deletions driver-core/src/main/com/mongodb/client/model/GeoNearOptions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* Copyright 2008-present MongoDB, Inc.
*
* 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 com.mongodb.client.model;

import org.bson.Document;
import org.bson.conversions.Bson;

/**
* The options for a {@link Aggregates#geoNear} pipeline stage.
*
* @mongodb.driver.manual reference/operator/aggregation/unwind/ $geoNear
* @since 4.8
*/
public interface GeoNearOptions extends Bson {
/**
* Returns {@link GeoNearOptions} that represents server defaults.
*
* @return {@link GeoNearOptions} that represents server defaults.
*/
static GeoNearOptions geoNearOptions() {
return GeoNearConstructibleBson.EMPTY_IMMUTABLE;
}

/**
* @param distanceMultiplier The factor to multiply all distances returned by the query.
* @return a new {@link GeoNearOptions} with the provided option set
* @since 4.8
*/
GeoNearOptions distanceMultiplier(Number distanceMultiplier);

/**
* This specifies the output field that identifies the location used to calculate the distance.
* This option is useful when a location field contains multiple locations.
* To specify a field within an embedded document, use dot notation.
*
* @param includeLocs the output field
* @return a new {@link GeoNearOptions} with the provided option set
* @since 4.8
*/
GeoNearOptions includeLocs(String includeLocs);

/**
* Specify the geospatial indexed field to use when calculating the distance.
*
* @param key the geospatial indexed field.
* @return a new {@link GeoNearOptions} with the provided option set
* @since 4.8
*/
GeoNearOptions key(String key);

/**
* The minimum distance from the center point that the documents can be.
* MongoDB limits the results to those documents that fall outside the specified distance from the center point.
*
* @param minDistance the distance in meters for GeoJSON data.
* @return a new {@link GeoNearOptions} with the provided option set
* @since 4.8
*/
GeoNearOptions minDistance(Number minDistance);

/**
* The maximum distance from the center point that the documents can be.
* MongoDB limits the results to those documents that fall within the specified distance from the center point.
*
* @param maxDistance the distance in meters for GeoJSON data.
* @return a new {@link GeoNearOptions} with the provided option set
* @since 4.8
*/
GeoNearOptions maxDistance(Number maxDistance);

/**
* Limits the results to the documents that match the query.
* The query syntax is the usual MongoDB read operation query syntax.
*
* @param query the query
* @return a new {@link GeoNearOptions} with the provided option set
* @since 4.8
*/
GeoNearOptions query(Document query);

/**
* Determines how MongoDB calculates the distance between two points.
* By default, when this option is not provided, MongoDB uses $near semantics:
* spherical geometry for 2dsphere indexes and planar geometry for 2d indexes.
* When provided, MongoDB uses $nearSphere semantics and calculates distances
* using spherical geometry.
*
* @return a new {@link GeoNearOptions} with the provided option set
* @since 4.8
*/
GeoNearOptions spherical();
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,19 @@ import static com.mongodb.internal.operation.OperationUnitSpecification.getMaxWi
class OperationFunctionalSpecification extends Specification {

def setup() {
setupInternal()
}

protected void setupInternal() {
ServerHelper.checkPool(getPrimary())
CollectionHelper.drop(getNamespace())
}

def cleanup() {
void cleanup() {
cleanupInternal()
}

protected void cleanupInternal() {
CollectionHelper.drop(getNamespace())
checkReferenceCountReachesTarget(getBinding(), 1)
checkReferenceCountReachesTarget(getAsyncBinding(), 1)
Expand Down
Loading