定义
- $geoNear
- 按距离指定点最近到最远的顺序输出文档。 - 注意- $geoNear阶段具有以下原型形式:- { $geoNear: { <geoNear options> } } - $geoNear运算符接受包含以下- $geoNear选项的文档。使用与已处理文档坐标系相同的单位指定所有距离:字段类型说明- distanceField- 字符串 - 包含计算出的距离的输出字段。要在嵌入式文档中指定字段,请使用点符号。 - 对时间序列集合进行查询时,此字段为必填项。从MongoDB 8.1 开始,对于对非时间序列集合的查询, - distanceField是可选的。- distanceMultiplier- 数字 - 可选。用于与查询返回的所有距离相乘的系数。例如,使用 - distanceMultiplier乘以地球半径,将球形查询返回的弧度转换为公里。- includeLocs- 字符串 - 可选。这指定了一个输出字段,用于标识用来计算距离的位置。该选项适合位置字段包含多个位置的情况。要在嵌入式文档中指定字段,请使用点符号。 - key- maxDistance- 数字 - minDistance- 数字 - 可选。 文档与中心点的最小距离。 MongoDB 将结果限制为与中心点相距指定距离之外的文档。 从版本 7.2 开始,您可以指定解析为数字的有效常量表达式。 - 对于 GeoJSON 数据,以米为单位指定距离;对于传统坐标对,以弧度为单位指定距离。 - near- GeoJSON 点或传统坐标对 - query- 文档 - spherical- 布尔 
行为
距离计算
$geoNear 根据输入文档周边的最近点计算距离。
示例,如果输入文档是一个形状,$geoNear 则会标识形状周长上距离指定点最近的点,并输出指定点与形状最近点之间的距离。
Considerations
在使用 $geoNear 时,请考虑:
- 只能使用 - $geoNear作为管道的第一阶段。
- 如果集合上有多个地理空间索引,请使用 - keys参数指定要在计算中使用的字段。如果你只有一个地理空间索引,- $geoNear会隐式使用索引字段进行计算。
- $geoNear不再有 100 个文档的默认限制。
- 从 MongoDB 5.1 开始, - near参数支持 let 选项和绑定 let 选项。
- 从 MongoDB 8.0、 - $near、- $nearSphere和- $geoNear开始,验证指定的 GeoJSON Point 的类型是否为- Point。任何其他输入类型都会返回错误。
示例
使用以下文档创建集合 places:
db.places.insertMany( [    {       name: "Central Park",       location: { type: "Point", coordinates: [ -73.97, 40.77 ] },       category: "Parks"    },    {       name: "Sara D. Roosevelt Park",       location: { type: "Point", coordinates: [ -73.9928, 40.7193 ] },       category: "Parks"    },    {       name: "Polo Grounds",       location: { type: "Point", coordinates: [ -73.9375, 40.8303 ] },       category: "Stadiums"    } ] ) 
下面的操作将在 location 字段上创建一个 2dsphere 索引:
db.places.createIndex( { location: "2dsphere" } ) 
最大距离
注意
上面的 places 集合有一个 2dsphere 索引。以下聚合使用 $geoNear 来查找距离中心 [ -73.99279 , 40.719296 ] 最多 2 米且 category 等于 Parks 的文档。
db.places.aggregate([    {      $geoNear: {         near: { type: "Point", coordinates: [ -73.99279 , 40.719296 ] },         distanceField: "dist.calculated",         maxDistance: 2,         query: { category: "Parks" },         includeLocs: "dist.location",         spherical: true      }    } ]) 
该聚合返回以下内容:
{    "_id" : 8,    "name" : "Sara D. Roosevelt Park",    "category" : "Parks",    "location" : {       "type" : "Point",       "coordinates" : [ -73.9928, 40.7193 ]    },    "dist" : {       "calculated" : 0.9539931676365992,       "location" : {          "type" : "Point",          "coordinates" : [ -73.9928, 40.7193 ]       }    } } 
匹配文档包含两个新字段:
- dist.calculated字段,其包含计算出的距离,以及
- dist.location字段,包含计算中使用的位置。
最小距离
注意
以下示例使用选项 minDistance 来指定文档可与中心点相距的最小距离。以下聚合查找距离中心 [ -73.99279 , 40.719296 ] 至少 2 米且 category 等于 Parks 的文档。
db.places.aggregate([    {      $geoNear: {         near: { type: "Point", coordinates: [ -73.99279 , 40.719296 ] },         distanceField: "dist.calculated",         minDistance: 2,         query: { category: "Parks" },         includeLocs: "dist.location",         spherical: true      }    } ]) 
带有 选项的 $geoNearlet
在本例中:
- let选项用于将- [-73.99279,40.719296]数组值设置为变量- $pt。
- $pt在- $geoNear阶段指定为- near参数的- let选项。
db.places.aggregate( [    {       "$geoNear":       {          "near":"$$pt",          "distanceField":"distance",          "maxDistance":2,          "query":{"category":"Parks"},          "includeLocs":"dist.location",          "spherical":true       }    } ], {    "let":{ "pt": [ -73.99279, 40.719296 ] } } ) 
该聚合返回包含以下内容的所有文档:
- 距离 - let变量中定义的点最多 2 米的位置
- category等于- Parks。
{    _id: ObjectId("61715cf9b0c1d171bb498fd7"),    name: 'Sara D. Roosevelt Park',    location: { type: 'Point', coordinates: [ -73.9928, 40.7193 ] },    category: 'Parks',    distance: 1.4957325341976439e-7,    dist: { location: { type: 'Point', coordinates: [ -73.9928, 40.7193 ] } } }, {    _id: ObjectId("61715cf9b0c1d171bb498fd6"),    name: 'Central Park',    location: { type: 'Point', coordinates: [ -73.97, 40.77 ] },    category: 'Parks',    distance: 0.0009348548688841822,    dist: { location: { type: 'Point', coordinates: [ -73.97, 40.77 ] } } } 
带有绑定 选项的 $geoNearlet
let 选项可以绑定用于 $geoNear 查询的变量。
在此示例中,$lookup 使用:
db.places.aggregate( [    {       $lookup: {          from: "places",          let: { pt: "$location" },          pipeline: [             {                $geoNear: {                   near: "$$pt",                   distanceField: "distance"                }             }          ],          as: "joinedField"       }    },    {       $match: { name: "Sara D. Roosevelt Park" }    } ] ); 
该聚合返回一个包含以下内容的文档:
- “Sara D. Roosevelt Park”文档作为主要文档。 
- 使用 - $pt变量将地点集合中的每个文档作为子文档来计算距离。
{    _id: ObjectId("61715cf9b0c1d171bb498fd7"),       name: 'Sara D. Roosevelt Park',       location: { type: 'Point', coordinates: [ -73.9928, 40.7193 ] },       category: 'Parks',       joinedField: [          {          _id: ObjectId("61715cf9b0c1d171bb498fd7"),          name: 'Sara D. Roosevelt Park',          location: { type: 'Point', coordinates: [ -73.9928, 40.7193 ] },          category: 'Parks',          distance: 0          },          {          _id: ObjectId("61715cf9b0c1d171bb498fd6"),          name: 'Central Park',          location: { type: 'Point', coordinates: [ -73.97, 40.77 ] },          category: 'Parks',          distance: 5962.448255234964          },          {          _id: ObjectId("61715cfab0c1d171bb498fd8"),          name: 'Polo Grounds',          location: { type: 'Point', coordinates: [ -73.9375, 40.8303 ] },          category: 'Stadiums',          distance: 13206.535424939102          }       ] } 
指定要使用的地理空间索引
考虑 places 集合,它在 location 字段上有 2dsphere 索引,在 legacy 字段上有 2d 索引。
places 集合中的文档类似于以下内容:
{    "_id" : 3,    "name" : "Polo Grounds",    "location": {       "type" : "Point",       "coordinates" : [ -73.9375, 40.8303 ]    },    "legacy" : [ -73.9375, 40.8303 ],    "category" : "Stadiums" } 
以下示例使用了 key 选项,具体指定聚合应使用 location 字段值来执行 $geoNear 操作,而不是使用 legacy 字段值。该管道还使用了 $limit,最多返回 5 个文档。
注意
db.places.aggregate([    {      $geoNear: {         near: { type: "Point", coordinates: [ -73.98142 , 40.71782 ] },         key: "location",         distanceField: "dist.calculated",         query: { "category": "Parks" }      }    },    { $limit: 5 } ]) 
该聚合返回以下内容:
{    "_id" : 8,    "name" : "Sara D. Roosevelt Park",    "location" : {       "type" : "Point",       "coordinates" : [          -73.9928,          40.7193       ]    },    "category" : "Parks",    "dist" : {       "calculated" : 974.175764916902    } } {    "_id" : 1,    "name" : "Central Park",    "location" : {       "type" : "Point",       "coordinates" : [          -73.97,          40.77       ]    },    "legacy" : [       -73.97,       40.77    ],    "category" : "Parks",    "dist" : {       "calculated" : 5887.92792958097    } } 
本页上的C#示例使用Atlas示例数据集中的 sample_mflix.theaters集合。要学习;了解如何创建免费的MongoDB Atlas 群集并加载示例数据集,请参阅MongoDB .NET/ C#驱动程序文档中的入门。
以下 Theater、Location 和 Address 类将为 sample_mflix.theaters 集合中的文档建模:
public class Theater {   public ObjectId Id { get; set; }   []   public int TheaterId { get; set; }   []   public Location Location { get; set; }   []   public double? Distance { get; set; } } public class Location {   []   public Address Address { get; set; }   []   public GeoJsonPoint<GeoJson2DGeographicCoordinates> Geo { get; set; } } [] public class Address {   []   public string City { get; set; }   []   public string State { get; set; } } 
要使用 MongoDB .NET/C# 驱动程序将$geoNear 阶段添加到聚合管道,请对 PipelineDefinition 对象调用 GeoNear() 方法。
此方法仅在MongoDB .NET/C#驱动程序v3.4 及更高版本中可用。
最大距离
以下示例创建一个管道阶段,该阶段返回位于指定点 8000 米半径范围内的文档,并按距离从近到远的顺序排列。该代码包含一个 Query 参数,仅匹配 location.address.state 字段的值为 "NJ" 的文档。代码还会将计算出的距离存储在输出文档的 distance 字段中。
var pipeline = new EmptyPipelineDefinition<Theater>()     .GeoNear(         GeoJson.Point(GeoJson.Geographic(-74.1, 40.95)),         new GeoNearOptions<Theater, Theater>         {           DistanceField = "distance",           MaxDistance = 8000,           Key = "location.geo",           Query = Builders<Theater>.Filter.Eq(t => t.Location.Address.State, "NJ"),         }); 
最小距离
以下示例按距离升序返回指定点8000 米半径之外的前 4 个匹配文档。该代码包含一个 Query 参数,该参数仅匹配 location.address.state字段值为 "NJ" 的文档。该代码还会将计算出的距离存储在输出文档的 distance字段中。
var pipeline = new EmptyPipelineDefinition<Theater>()     .GeoNear(         GeoJson.Point(GeoJson.Geographic(-74.1, 40.95)),         new GeoNearOptions<Theater, Theater>         {           DistanceField = "distance",           MinDistance = 8000,           Key = "location.geo",           Query = Builders<Theater>.Filter.Eq(t => t.Location.Address.State, "NJ"),         })     .Limit(4); 
本页上的 Node.js 示例使用 Atlas 示例数据集中的 sample_mflix数据库。要学习如何创建免费的MongoDB Atlas 集群并加载示例数据集,请参阅MongoDB Node.js驱动程序文档中的入门。
要使用MongoDB Node.js驱动程序将 $geoNear 阶段添加到聚合管道,请在管道对象中使用 $geoNear操作符。
最大距离
以下示例创建了一个管道阶段,该阶段按距离升序返回指定点半径 8000 米内的文档。该代码包含一个 query字段,该字段仅匹配 location.address.state字段值为 "NJ" 的文档。该代码还会将计算出的距离存储在输出文档的 distance字段中。然后,该示例运行聚合管道:
const pipeline = [   {     $geoNear: {       near: {         type: "Point",         coordinates: [-74.1, 40.95]       },       distanceField: "distance",       maxDistance: 8000,       query: { "location.address.state": "NJ" },       spherical: true     }   } ]; const cursor = collection.aggregate(pipeline); return cursor; 
最小距离
以下示例按距离升序返回指定点8000 米半径之外的前 4 个匹配文档。该代码包含一个 query字段,该字段仅匹配 location.address.state字段值为 "NJ" 的文档。此代码还会将计算出的距离存储在输出文档的 distance字段中:
const pipeline = [   {     $geoNear: {       near: {         type: "Point",         coordinates: [-74.1, 40.95]       },       distanceField: "distance",       minDistance: 8000,       query: { "location.address.state": "NJ" },       spherical: true     },   },   { $limit: 4 } ]; const cursor = collection.aggregate(pipeline); return cursor; 
了解详情
要学习;了解有关相关管道阶段的更多信息,请参阅 $limit 指南。