【问题标题】:MongoDB find by origin and destinationMongoDB按来源和目的地查找
【发布时间】:2020-11-09 02:47:35
【问题描述】:

我有一个用于运输卡车的 MongoDB 集合,该集合具有起点坐标和目的地坐标以及每个坐标的半径值,以确定卡车愿意开多远来取件/放下包裹。就这样……

origin:{ 
 location { coordinates:[ 40.7128, 74.006 ] }, 
 radius:25 
}
destination:{ 
 location { coordinates:[ 34.0522, 118.2437 ] }, 
 radius:25 
}

问题是我不认为 MongoDB 会让我有两个 2dsphere 索引。

我如何查询集合中的卡车,其起点和终点都在到给定点的半径范围内?

【问题讨论】:

  • 我会调查使用 $expr 的条件之一(选择性较低的条件)。

标签: javascript node.js mongodb mongoose mongodb-query


【解决方案1】:

这是我根据haversine formula 得出的结论

.aggregate({
    $addFields: { distanceToDestination: {
      $multiply: [6371000,
        { $multiply: [2, { $atan2: [{ $sqrt: { $add: [
          { $multiply: [
            { $sin: { $divide: [{ $degreesToRadians: { $subtract: [{ $arrayElemAt: ['$destination.location.coordinates', 1] }, Number(destinationLatitude)] } }, 2] } },
            { $sin: { $divide: [{ $degreesToRadians: { $subtract: [{ $arrayElemAt: ['$destination.location.coordinates', 1] }, Number(destinationLatitude)] } }, 2] } },
          ] },
          { $multiply: [
            { $cos: { $degreesToRadians: Number(destinationLatitude) } },
            { $cos: { $degreesToRadians: { $arrayElemAt: ['$destination.location.coordinates', 1] } } },
            { $sin: { $divide: [{ $degreesToRadians: { $subtract: [{ $arrayElemAt: ['$destination.location.coordinates', 0] }, Number(destinationLongitude)] } }, 2] } },
            { $sin: { $divide: [{ $degreesToRadians: { $subtract: [{ $arrayElemAt: ['$destination.location.coordinates', 0] }, Number(destinationLongitude)] } }, 2] } },
          ] },
        ] } },
        { $sqrt: { $subtract: [1, { $add: [
          { $multiply: [
            { $sin: { $divide: [{ $degreesToRadians: { $subtract: [{ $arrayElemAt: ['$destination.location.coordinates', 1] }, Number(destinationLatitude)] } }, 2] } },
            { $sin: { $divide: [{ $degreesToRadians: { $subtract: [{ $arrayElemAt: ['$destination.location.coordinates', 1] }, Number(destinationLatitude)] } }, 2] } },
          ] },
          { $multiply: [
            { $cos: { $degreesToRadians: Number(destinationLatitude) } },
            { $cos: { $degreesToRadians: { $arrayElemAt: ['$destination.location.coordinates', 1] } } },
            { $sin: { $divide: [{ $degreesToRadians: { $subtract: [{ $arrayElemAt: ['$destination.location.coordinates', 0] }, Number(destinationLongitude)] } }, 2] } },
            { $sin: { $divide: [{ $degreesToRadians: { $subtract: [{ $arrayElemAt: ['$destination.location.coordinates', 0] }, Number(destinationLongitude)] } }, 2] } },
          ] },
        ] }] } }] }] },
      ],
    } },
  },{ $match: { $expr: { $lt: ['$distanceToDestination', { $multiply: ['$destination.radius', 1609] }] } } })

【讨论】:

    【解决方案2】:

    我遇到了同样的问题,最后我使用了不需要 2d/2dsphere 索引的$geowithin query with $centersphere

    //collection example
    {
      "origin": {
        "type": "Point",
        "coordinates": [-119.158323, 34.177169]//<longitude>, <latitude>              
      },                
      "destination": {
        "type": "Point",
        "coordinates": [-117.274471, 32.832215]//<longitude>, <latitude>              
      }
    }
    

    注意:我在示例中使用了GeoJSON objects 来存储坐标。 $centersphere 还支持根据the documentation 的旧坐标对。

    const originCoords: [-119.159392, 34.164958];//query params
    const destCoords:  [-117.221505, 32.873788 ];//query params
    const distInRadians = 25 / 3963.2;//converts the distance from miles to radians by dividing by the approximate equatorial radius of the earth
    
    collection.find({
      origin: { $geoWithin: { $centerSphere: [ originCoords, distInRadians ] } },
      destination:{ $geoWithin: { $centerSphere: [ destCoords, distInRadians ] } }
    }).toArray(function(err,results) {
       //processing query results here
    });
    
    

    希望这个答案会有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多