翻译或纠错本页面

使用球面几何计算距离

注解

虽然 2d 索引支持在基本查询中使用球面距离,您可以考虑转换到 2dsphere 索引,如果您的数据都是经度和纬度。

MongoDB在 2d 索引支持在欧几里德平面上计算距离的查询。该类索引还支持如下使用球面几何来计算距离的索引操作符和命令:

重要

These three queries use radians for distance. Other query types do not.

为了确保球面操作符能计算正确,您必须将距离转换成弧度,以及将弧度转换为距离,单位是您的应用所需要的单位。

转换如下:

  • 从距离到弧度: 将距离除以球面的半径(例如地球半径),两者单位一致。

  • 从弧度到距离:将弧度乘以球面半径(例如地球半径),单位换算成您所希望使用的单位。

The equatorial radius of the Earth is approximately 3,963.2 miles or 6,378.1 kilometers.

如下查询会从 places 集合中返回在圆内部的文档,这个圆的圆心是 [ -74, 40.74 ] ,半径是 100

db.places.find( { loc: { $geoWithin: { $centerSphere: [ [ -74, 40.74 ] ,
                                                     100 / 3963.2 ] } } } )

您也可以在 geoNear 中使用 distanceMultiplier 选项,在 mongod 程序中将弧度转换为距离。而不是在您的应用代码中。参见 distance multiplier

如下球面查询会返回 places 集合中距离点 [ -74, 40.74 ]100 英里的所有文档。

db.runCommand( { geoNear: "places",
                 near: [ -74, 40.74 ],
                 spherical: true
               }  )

以上的输出如下:

{
   // [ ... ]
   "results" : [
      {
         "dis" : 0.01853688938212826,
         "obj" : {
            "_id" : ObjectId( ... )
            "loc" : [
               -73,
               40
            ]
         }
      }
   ],
   "stats" : {
      // [ ... ]
      "avgDistance" : 0.01853688938212826,
      "maxDistance" : 0.01853714811400047
   },
   "ok" : 1
}

警告

球面查询中的条件如果环绕着南/北极或者在 -180180 经度的交界过渡区,会导致错误。

注解

虽然地理索引的默认的类地球面边界是大于等于 -180 到小于 180 间,纬度的合理值却是在 -9090 间。

距离系数 - Distance Multiplier

带有 distanceMultiplier 选项的 geoNear 命令可以在将结果和给定值相乘后再返回。这可以让MongDB返回转换后的值,免除了在应用逻辑中转换单位的需要。

在球面查询中使用 distanceMultiplier 会返回和 geoNear 命令相同的结果,都不需要弧度-到-距离的转换。如下示例中,在 geoNear 命令中使用 distanceMultiplierspherical 参数:

db.runCommand( { geoNear: "places",
                 near: [ -74, 40.74 ],
                 spherical: true,
                 distanceMultiplier: 3963.2
               }  )

The output of the above operation would resemble the following:

{
   // [ ... ]
   "results" : [
      {
         "dis" : 73.46525170413567,
         "obj" : {
            "_id" : ObjectId( ... )
            "loc" : [
               -73,
               40
            ]
         }
      }
   ],
   "stats" : {
      // [ ... ]
      "avgDistance" : 0.01853688938212826,
      "maxDistance" : 0.01853714811400047
   },
   "ok" : 1
}