简体   繁体   English

通过过滤按最接近的地理位置对数据进行排序

[英]Sort data by closest geolocation with filtering

I am trying to locate correct building where someone is using my application in. Right now i have managed to do a pretty bad filtering and i need to improve it. 我试图找到某人正在使用我的应用程序的正确建筑物。现在,我已经设法进行了非常糟糕的筛选,我需要对其进行改进。

What my goal is with filtering to return the closest building to the person using the application, so filter it as good as possible without creating errors when moving around in the same building. 我的目标是通过过滤将最接近的建筑物归还给使用该应用程序的人,因此,在同一建筑物中四处走动时,尽可能对其进行尽可能好的过滤而不会产生错误。

My fetch returns an api JSON array that looks like this: 我的提取返回的api JSON数组如下所示:

{
"data": [
{
  "id": 1,
  "city": "CITY",
  "building_name": "Building 1",
  "building_address": "Address 123",
  "latitude":  "57.7052809",
  "longitude": "16.9367817"
},
{
  "id": 2,
  "city": "CITY",
  "building_name": "Building 2",
  "building_address": "Address 456",
  "latitude":  "35.7054509",
  "longitude": "16.9366141"
}
],
}

This is my code 这是我的代码

fetch('http://localhost:8888/api/buildings')
.then(response => response.json())
.then(data => {

  userCoordinates = {
    latitude:  35.7053509,
    longitude: 16.9362301
  }


  const returnedBuilding = Object.entries(data.data).map(([inst, key]) => key)
  .filter(thing => (thing.latitude > userCoordinates.latitude - .5 &&
     thing.latitude < userCoordinates.latitude + .5) &&
      (thing.longitude > userCoordinates.longitude -.5 &&
       thing.longitude < userCoordinates.longitude + .5));

       console.log(returnedBuilding);

})

Use 'distance' between two points to find the closest. 在两点之间使用“距离”来找到最接近的点。 You can't guarantee the user's building but you can guarantee which one is closest with respect to user's co-ordinate. 您不能保证用户的建筑物,但是可以保证相对于用户坐标最接近的建筑物。

var keys = Object.entries(data.data).map(([inst, key]) => key);
var returnedBuilding = 
  keys.reduce((prevCord, thing) => {
    var dist = getDistance(userCoordinates.latitude, userCoordinates.longitude, thing.latitude, thing.longitude);
    var prevDist = getDistance(userCoordinates.latitude, userCoordinates.longitude, prevCord.latitude, prevCord.longitude);
    return dist < prevDist? thing : prevCord;
}, keys[0]);

Below is the getDistance function, I referred from this post . 下面是我从本文中引用的getDistance函数。 However you can write your own, a simpler one as you are dealing with small distances only (I assume). 但是,您可以编写自己的,更简单的代码,因为您只处理小距离(我认为)。

function getDistance(lat1, lon1, lat2, lon2) 
{
  var R = 6371; // km
  var dLat = toRad(lat2-lat1);
  var dLon = toRad(lon2-lon1);
  var lat1 = toRad(lat1);
  var lat2 = toRad(lat2);

  var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
    Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); 
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
  var d = R * c;
  return d;
}

// Converts numeric degrees to radians
function toRad(Value) 
{
    return Value * Math.PI / 180;
}

You could use a haversine formula to determine which building is the closest. 您可以使用Haversine公式来确定最接近的建筑物。

The haversine formula determines the great-circle distance between two points on a sphere given their longitudes and latitudes. Haversine公式根据给定的经度和纬度确定球体上两个点之间的大圆距离。 tl;dr, you can do this to find the distance between yourself and the buildings and then accurately determine which is the closest. tl; dr,您可以执行此操作以找到您自己与建筑物之间的距离,然后准确确定最接近的建筑物。

Here's another article from SO about using it in javascript: Using the Haversine Formula in Javascript 这是SO的另一篇有关在javascript中使用它的文章: 在Javascript中使用Haversine公式

You could loop through each building and find the closest one based on distance 您可以遍历每座建筑物并根据距离找到最接近的建筑物

var closestBuilding = building[0];
var closestDistance = distanceFrom(user, building);
building.forEach(function(building) {
  var distanceFrom = distanceFrom(user, building);
  if(closestDistance > distanceFrom){
    closestBuilding = building;
    closestDistance = distanceFrom;
  } 
})
console.log(closestBuilding);

function distanceFrom(user, building) { /* your distance code */ }

I would highly recommend looking into changing your data model to utilize GeoJSON points stored in a mongoDB database. 我强烈建议您研究更改数据模型以利用存储在mongoDB数据库中的GeoJSON点。 That will allow you to leverage mongoDB's powerful built in geospatial queries . 这将使您能够利用mongoDB强大的内置地理空间查询 Using your existing data model above as a starting point, your new data model could look something like this: 使用上面的现有数据模型作为起点,新数据模型可能如下所示:

{
  "id": 1,
  "city": "CITY",
  "building_name": "Building 1",
  "building_address": "Address 123",
  "location": {
    "type": "Point",
    "coordinates": [ // IMPORTANT: note the order is longitude, latitude
      16.9367817, // longitude
      57.7052809, // latitude
    ]
  }
}

The location property in the object above is the GeoJSON point. 上面对象中的location属性是GeoJSON点。 Now, rather than fetching every location from your database and doing the calculation yourself in the client, you would query your buildings database for the closest buildings to the user's location. 现在,您可以从建筑物数据库中查询与用户位置最近的建筑物,而不是从数据库中获取每个位置并自行在客户端中进行计算。 Assuming user coordinates are latitude: 35.7053509 , longitude: 16.9362301 , your query could look something like this (via a GET request): 假设用户坐标为latitude: 35.7053509longitude: 16.9362301 ,则查询可能看起来像这样(通过GET请求):

http://localhost:8888/api/buildings?lat=35.7053509&lng=16.9362301&maxDistance=2000

The mongoDB documentation provides examples for how to handle geospatial queries. mongoDB文档提供了有关如何处理地理空间查询的示例。 This example is taken from the documentation, and is how your api would process the request: 此示例摘自文档,是您的api处理请求的方式:

// If you're using express.js, pull the params off the query object
const { lat, lng, maxDistance } = req.query;
const buildings = db.buildings.find(
  {
    location:
      {
        $near:
          {
            $geometry: { type: "Point", coordinates: [lng, lat] },
            $maxDistance: maxDistance
          }
      }
  }
)
  .then(buildings => res.json({ buildings })) // respond to the client
  .catch(err => console.log(err)) // do something with the error

The response from your server would be a list of all buildings within the specified maxDistance , sorted by distance from the user's location (closest to furthest). 服务器的响应将是指定maxDistance内所有建筑物的列表, maxDistance距用户位置(最接近)的距离排序。 MongoDB geospatial queries are incredibly fast and performant. MongoDB地理空间查询非常快速且高效。 You could even slice the first result from the db.find operation and return a single building from your api if your client only wants a single result. 如果您的客户端只需要一个结果,您甚至可以对db.find操作的第一个结果进行切片,并从api返回单个建筑。

Hope this makes sense and helps! 希望这有意义并有所帮助! Might seem a little daunting at first if you haven't worked with mongoDB and/or geoJSON objects, but trust me, this will make your life SO much easier. 如果您还没有使用mongoDB和/或geoJSON对象,一开始可能会有些畏缩,但是请相信我,这将使您的生活变得如此轻松。 Another little gotcha can occur when your are setting up your database and collection. 当您设置数据库和集合时,可能会出现另一个小问题。 You need to make sure to add an index the buildings collection to support geospatial queries. 您需要确保为建筑物集合添加索引以支持地理空间查询。 From the documentation: 从文档中:

db.buildings.createIndex( { location: "2dsphere" } )

Then create your collection and add your building documents to it. 然后创建您的收藏并向其中添加建筑文档。

Feel free follow up if you need any clarification. 如果需要任何澄清,请随时跟进。 I'd suggest reading through mongoDB's documentation and search for more examples online. 我建议您阅读mongoDB的文档并在线搜索更多示例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM