在聚合管道阶段计算以千米为单位的距离点

时间:2018-04-30 02:47:10

标签: mongodb aggregation-framework

此文档由聚合管道阶段返回:

//1
{
    "_id" : {
        "h" : 8,
        "d" : 6,
        "m" : 3,
        "y" : 2017
    },
    "docs" : [ ....],
"firstDoc" : {
    "ts" : ISODate("2017-03-06T08:07:21.008Z"),
    "coordinate" : [ 
        59.5......, 
        36.2......
    ]
   }
} ,
//2
{

} , // 3 , 4 

我有4个文件如上所述,这些firstDoc字段不同。现在我想计算以公里为单位的点之间的距离。像这样:

coordinate1---km?---coordinate2
coordinate2---km?---coordinate3
coordinate3---km?---coordinate4

我看到这个link但我不使用GeoJSON而我不想proximity。我想计算点之间的距离我该怎么做? 我搜索了很多,但我在mongoDB中找不到任何结果!!

我看到人们通过其他语言(例如java和c#和java Script来执行此操作,但没有人使用mongo查询。 是否有可能使用mongoDB?

1 个答案:

答案 0 :(得分:1)

实际上它覆盖在第一个链接中,因为"distanceMultipler"字段可用于在数据未存储在GeoJSON中并使用传统坐标对时返回的“弧度”之间进行转换以任何可接受的格式。

来自"distanceField"选项的$geoNear文档:

  

可选。乘以查询返回的所有距离的因子。例如,使用distanceMultiplier将球形查询返回的弧度转换为乘以地球半径的千米。

来自Calculate Distance Using Spherical Geometry

  
      
  • 到弧度的距离:将距离除以球体半径(例如地球),与距离测量值相同。
  •   
  • 弧度到距离:将弧度量乘以要转换距离的单位系统中球体半径(例如地球)。
  •   
     

地球的赤道半径约为3,963.2英里或6,378.1公里。

因此,您只需填写选项:

db.collection.aggregate([
  { "$geoNear": {
    "near": [<longitude>,<latitude>],
    "distanceField": "distance",
    "spherical": true,
    "distanceMultiplier": 6378.1      // convert radians to kilometers
  }}
])

或者,如果您确实仔细阅读了文档,您会看到"near"选项提供给"spherical"的条件存在特殊情况:

  

如果为true,那么如果指定的(近)点是GeoJSON点,MongoDB使用球面几何计算以米为单位的距离,如果指定的(近)点是遗留坐标对,则使用弧度计算。

因此,无论存储格式如何,只需提供GeoJSON格式的查询坐标,就会返回

db.collection.aggregate([
  { "$geoNear": {
    "near": {
      "type": "Point",
      "coordinates": [<longitude>,<latitude>]
    },
    "distanceField": "distance",
    "spherical": true
  }}
])

另请注意,与其他“查询”运算符不同,$geoNear聚合管道阶段要求您在集合上只有一个地理空间索引。您无法指定要查询的“字段名称”,因为命令格式期望集合中存在 "2d""2dsphere"类型的唯一索引。你应该只需要一个,但你应该知道这一点。

$geoNear强制性选项当然是"near"要搜索的坐标的参数,以及返回实际计算距离的"distanceField"在退回的文件中。 "spherical"索引需要"2dsphere",您应该使用它来进行准确测量,当然"distanceMultiplier"是完全可选的,但会影响{{1}指定的属性中返回的结果{1}}。

根据您是否需要其他查询条件或约束,还有其他选项,但这些是本练习中的主要选项。

另请注意"distanceField""longitude"订单。这是强制性,以便MongoDB地理空间查询正常工作。如果您的数据反转了这些值(可能是从其他API获取的情况),那么您需要通过简单地反转存储的订单或更好地完全转换为GeoJSON来纠正它。

GeoJSON转换

当然,另一种选择是简单地更新您的数据以实际使用GeoJSON格式:

"latitude"

然后删除任何先前的索引并创建新索引:

var ops = [];
db.colllection.find({ "coordinate": { "$exists": true } }).forEach( doc => {
  ops.push({
    "updateOne": {
      "filter": { "_id": doc._id },
      "update": {
        "$set": { "location": { "type": "Point", "coordinates": doc.coordinate } },
        "$unset": { "coordinate": "" }
      }
    }
  });

  if ( ops.length >= 1000 ) {
    db.collection.bulkWrite(ops);
    ops = [];
  }
})

if ( ops.length > 0 ) {
  db.collection.bulkWrite(ops);
  ops = [];
}

当然,在所有情况下都会为您的实际收藏名称交换db.collection.dropIndex({ "coordinate": "2dpshere" }) db.collection.createIndex({ "location": "2dsphere" })

然后您也可以使用GeoJSON参数进行查询,并按照标准简单地以米为单位返回距离。

两者都是可行的选项,但真正使用GeoJSON应该保持与大多数其他外部库使用的兼容性,并保持对所有MongoDB地理空间查询操作的支持。