Skip to content

Commit 3155c39

Browse files
authored
CSHARP-5505: Add $geoNear stage aggregation builders (#1621)
1 parent 1d0c791 commit 3155c39

11 files changed

+548
-847
lines changed

src/MongoDB.Driver/Core/Misc/Feature.cs

+2
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@ public class Feature
311311
/// <summary>
312312
/// Gets the geoNear command feature.
313313
/// </summary>
314+
///
315+
[Obsolete("This property will be removed in a later release.")]
314316
public static Feature GeoNearCommand => __geoNearCommand;
315317

316318
/// <summary>

src/MongoDB.Driver/Core/Operations/GeoNearOperation.cs

-190
This file was deleted.

src/MongoDB.Driver/GeoNearOptions.cs

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using MongoDB.Bson.Serialization;
17+
18+
namespace MongoDB.Driver
19+
{
20+
/// <summary>
21+
/// Represents options for the $geoNear stage.
22+
/// </summary>
23+
public class GeoNearOptions<TInputDocument, TOutputDocument>
24+
{
25+
/// <summary>
26+
/// Gets or sets the output field that contains the calculated distance. Required if querying a time-series collection.
27+
/// Optional for non-time series collections in MongoDB 8.1+
28+
/// </summary>
29+
public FieldDefinition<TOutputDocument> DistanceField { get; set; }
30+
31+
/// <summary>
32+
/// Gets or sets the factor to multiply all distances returned by the query.
33+
/// </summary>
34+
public double? DistanceMultiplier { get; set; }
35+
36+
/// <summary>
37+
/// Gets or sets the output field that identifies the location used to calculate the distance.
38+
/// </summary>
39+
public FieldDefinition<TOutputDocument> IncludeLocs { get; set; }
40+
41+
/// <summary>
42+
/// Gets or sets the geospatial indexed field used when calculating the distance.
43+
/// </summary>
44+
public string Key { get; set; }
45+
46+
/// <summary>
47+
/// Gets or sets the max distance from the center point that the documents can be.
48+
/// </summary>
49+
public double? MaxDistance { get; set; }
50+
51+
/// <summary>
52+
/// Gets or sets the min distance from the center point that the documents can be.
53+
/// </summary>
54+
public double? MinDistance { get; set; }
55+
56+
/// <summary>
57+
/// Gets or sets the output serializer.
58+
/// </summary>
59+
public IBsonSerializer<TOutputDocument> OutputSerializer { get; set; }
60+
61+
/// <summary>
62+
/// Gets or sets the query that limits the results to the documents that match the query.
63+
/// </summary>
64+
public FilterDefinition<TInputDocument> Query { get; set; }
65+
66+
/// <summary>
67+
/// Gets or sets the spherical option which determines how to calculate the distance between two points.
68+
/// </summary>
69+
public bool? Spherical { get; set; }
70+
}
71+
}

src/MongoDB.Driver/IAggregateFluentExtensions.cs

+39
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
using MongoDB.Bson;
2323
using MongoDB.Bson.Serialization;
2424
using MongoDB.Driver.Core.Misc;
25+
using MongoDB.Driver.GeoJsonObjectModel;
2526

2627
namespace MongoDB.Driver
2728
{
@@ -252,6 +253,44 @@ public static IAggregateFluent<TNewResult> Facet<TResult, TNewResult>(
252253
return aggregate.AppendStage(PipelineStageDefinitionBuilder.Facet<TResult, TNewResult>(facets));
253254
}
254255

256+
/// <summary>
257+
/// Appends a $geoNear stage to the pipeline.
258+
/// </summary>
259+
/// <typeparam name="TResult">The type of the result.</typeparam>
260+
/// <typeparam name="TNewResult">The type of the new result.</typeparam>
261+
/// <typeparam name="TCoordinates">The type of the coordinates for the point.</typeparam>
262+
/// <param name="aggregate">The aggregate.</param>
263+
/// <param name="near">The point for which to find the closest documents.</param>
264+
/// <param name="options">The options.</param>
265+
/// <returns>The fluent aggregate interface.</returns>
266+
public static IAggregateFluent<TNewResult> GeoNear<TResult, TCoordinates, TNewResult>(
267+
this IAggregateFluent<TResult> aggregate,
268+
GeoJsonPoint<TCoordinates> near,
269+
GeoNearOptions<TResult, TNewResult> options = null)
270+
where TCoordinates : GeoJsonCoordinates
271+
{
272+
Ensure.IsNotNull(aggregate, nameof(aggregate));
273+
return aggregate.AppendStage(PipelineStageDefinitionBuilder.GeoNear<TResult, GeoJsonPoint<TCoordinates>, TNewResult>(near, options));
274+
}
275+
276+
/// <summary>
277+
/// Appends a $geoNear stage to the pipeline.
278+
/// </summary>
279+
/// <typeparam name="TResult">The type of the result.</typeparam>
280+
/// <typeparam name="TNewResult">The type of the new result.</typeparam>
281+
/// <param name="aggregate">The aggregate.</param>
282+
/// <param name="near">The point for which to find the closest documents.</param>
283+
/// <param name="options">The options.</param>
284+
/// <returns>The fluent aggregate interface.</returns>
285+
public static IAggregateFluent<TNewResult> GeoNear<TResult, TNewResult>(
286+
this IAggregateFluent<TResult> aggregate,
287+
double[] near,
288+
GeoNearOptions<TResult, TNewResult> options = null)
289+
{
290+
Ensure.IsNotNull(aggregate, nameof(aggregate));
291+
return aggregate.AppendStage(PipelineStageDefinitionBuilder.GeoNear<TResult, TNewResult>(near, options));
292+
}
293+
255294
/// <summary>
256295
/// Appends a $graphLookup stage to the pipeline.
257296
/// </summary>

src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Stages/AstGeoNearStage.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public AstGeoNearStage(
4545
string key)
4646
{
4747
_near = Ensure.IsNotNull(near, nameof(near));
48-
_distanceField = Ensure.IsNotNull(distanceField, nameof(distanceField));
48+
_distanceField = distanceField;
4949
_spherical = spherical;
5050
_maxDistance = maxDistance;
5151
_query = query;
@@ -80,7 +80,7 @@ public override BsonValue Render()
8080
{ "$geoNear", new BsonDocument
8181
{
8282
{ "near", _near },
83-
{ "distanceField", _distanceField },
83+
{ "distanceField", _distanceField, _distanceField != null },
8484
{ "spherical", () => _spherical.Value, _spherical.HasValue },
8585
{ "maxDistance", () => _maxDistance.Value, _maxDistance.HasValue },
8686
{ "query", _query, _query != null },

src/MongoDB.Driver/PipelineDefinitionBuilder.cs

+41
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
using MongoDB.Bson;
2121
using MongoDB.Bson.Serialization;
2222
using MongoDB.Driver.Core.Misc;
23+
using MongoDB.Driver.GeoJsonObjectModel;
2324
using MongoDB.Driver.Search;
2425

2526
namespace MongoDB.Driver
@@ -484,6 +485,46 @@ public static PipelineDefinition<TInput, TInput> For<TInput>(IBsonSerializer<TIn
484485
return new EmptyPipelineDefinition<TInput>(inputSerializer);
485486
}
486487

488+
/// <summary>
489+
/// Appends a $geoNear stage to the pipeline.
490+
/// </summary>
491+
/// <typeparam name="TInput">The type of the input documents.</typeparam>
492+
/// <typeparam name="TIntermediate">The type of the intermediate documents.</typeparam>
493+
/// <typeparam name="TOutput">The type of the output documents.</typeparam>
494+
/// <typeparam name="TCoordinates">The type of the coordinates for the point.</typeparam>
495+
/// <param name="pipeline">The pipeline.</param>
496+
/// <param name="near">The point for which to find the closest documents.</param>
497+
/// <param name="options">The options.</param>
498+
/// <returns>A new pipeline with an additional stage.</returns>
499+
public static PipelineDefinition<TInput, TOutput> GeoNear<TInput, TIntermediate, TCoordinates, TOutput>(
500+
this PipelineDefinition<TInput, TIntermediate> pipeline,
501+
GeoJsonPoint<TCoordinates> near,
502+
GeoNearOptions<TIntermediate, TOutput> options = null)
503+
where TCoordinates : GeoJsonCoordinates
504+
{
505+
Ensure.IsNotNull(pipeline, nameof(pipeline));
506+
return pipeline.AppendStage(PipelineStageDefinitionBuilder.GeoNear(near, options));
507+
}
508+
509+
/// <summary>
510+
/// Appends a $geoNear stage to the pipeline.
511+
/// </summary>
512+
/// <typeparam name="TInput">The type of the input documents.</typeparam>
513+
/// <typeparam name="TIntermediate">The type of the intermediate documents.</typeparam>
514+
/// <typeparam name="TOutput">The type of the output documents.</typeparam>
515+
/// <param name="pipeline">The pipeline.</param>
516+
/// <param name="near">The point for which to find the closest documents.</param>
517+
/// <param name="options">The options.</param>
518+
/// <returns>A new pipeline with an additional stage.</returns>
519+
public static PipelineDefinition<TInput, TOutput> GeoNear<TInput, TIntermediate, TOutput>(
520+
this PipelineDefinition<TInput, TIntermediate> pipeline,
521+
double[] near,
522+
GeoNearOptions<TIntermediate, TOutput> options = null)
523+
{
524+
Ensure.IsNotNull(pipeline, nameof(pipeline));
525+
return pipeline.AppendStage(PipelineStageDefinitionBuilder.GeoNear(near, options));
526+
}
527+
487528
/// <summary>
488529
/// Appends a $graphLookup stage to the pipeline.
489530
/// </summary>

0 commit comments

Comments
 (0)