$geoNear(聚合)
定义
$geoNear
按距离指定点最近到最远的顺序输出文档。
注意
$geoNear
阶段具有以下原型形式:{ $geoNear: { <geoNear options> } } $geoNear
运算符接受包含以下$geoNear
选项的文档。使用与已处理文档坐标系相同的单位指定所有距离:字段类型说明distanceField
字符串包含计算出的距离的输出字段。要在嵌入式文档中指定字段,请使用点符号。distanceMultiplier
数字可选。用于与查询返回的所有距离相乘的系数。例如,使用distanceMultiplier
乘以地球半径,将球形查询返回的弧度转换为公里。includeLocs
字符串可选。这指定了一个输出字段,用于标识用来计算距离的位置。该选项适合位置字段包含多个位置的情况。要在嵌入式文档中指定字段,请使用点符号。key
可选。指定计算距离时使用的地理空间索引字段。
如果您的集合有多个
2d
和/或多个2dsphere
索引,则必须使用key
选项来指定要使用的带索引字段路径。“指定要使用的地理空间索引”中提供了一个完整示例。如果存在多个
2d
索引或多个2dsphere
索引,并且您未指定key
,MongoDB 将返回错误。如果未指定
key
,并且您最多只有一个2d
索引和/或只有一个2dsphere
索引,MongoDB 首先会查找要使用的2d
索引。如果2d
索引不存在,则 MongoDB 会查找要使用的2dsphere
索引。maxDistance
数字minDistance
数字可选。 文档与中心点的最小距离。 MongoDB 将结果限制为与中心点相距指定距离之外的文档。 从版本 7.2 开始,您可以指定解析为数字的有效常量表达式。
对于 GeoJSON 数据,以米为单位指定距离;对于传统坐标对,以弧度为单位指定距离。
near
GeoJSON 点或传统坐标对query
文档spherical
布尔
行为
在使用 $geoNear
时,请考虑:
只能使用
$geoNear
作为管道的第一阶段。必须包含
distanceField
选项。distanceField
选项指定包含计算出的距离的字段。如果集合上有多个地理空间索引,请使用
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 } }