【问题标题】:sort results by the distance from a location javascript按与位置 javascript 的距离对结果进行排序
【发布时间】:2012-06-15 01:05:47
【问题描述】:

我有一张桌子,例如:

CREATE TABLE places (id UNIQUE, name, latitude, longitude)

然后我遍历我的数据集并计算用户位置和我的行之间的距离,然后我在 HTML 中显示为一个列表。

我的问题是我不知道如何按距离的升序对这个列表进行排序。

我是否将距离保存回 Places 表中,然后使用升序执行另一个 Select *...?

我可以不做一些事情,比如选择我的结果,而是通过运行一个 javascript 函数来排序它们。基本上是这样的:

tx.executeSql('select * from places order by ' 
function getdistance(userLat, UserLong, places.latitude, places.longitude)

谢谢,

【问题讨论】:

    标签: javascript sql sqlite


    【解决方案1】:

    我提供了Haversine Distance formula 的实现,您可以使用它来计算两个经度/纬度对之间距离的近似值。返回的距离可以是任何距离单位,只要您知道该单位中的地球半径即可。对于这个例子,我以千米和英里为单位提供了地球的半径。

    请注意传递索引为 0 的经度和索引为 1 的纬度的数组,因为此函数是为处理 GSON 样式的位置数据而编写的。

    您必须先进行 SQL 查询,然后在查询结果可用后计算距离。

    var earth_radius = {
      kilometers: 6371,
      miles: 3959
    };
    
    function toRad(x) {
      return x * Math.PI / 180;
    };
    
    // starting point: [<Float> longitude, <Float> latitude]
    // ending point: [<Float> longitude, <Float> latitude]
    // units: <Number> earth_radius
    function haversineDistance(starting_point, end_point, units) {
      units || (units = 1);
    
      var lat1 = parseFloat(starting_point[1]),
          lat2 = parseFloat(end_point[1]);
    
      var lon1 = parseFloat(starting_point[0]),
          lon2 = parseFloat(end_point[0]);
    
      var dLat = toRad(lat2 - lat1),
          dLon = toRad(lon2 - lon1);
    
      lat1 = toRad(lat1);
      lat2 = toRad(lat2);
    
      var arc = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
      return (2 * Math.atan2(Math.sqrt(arc), Math.sqrt(1 - arc))) * units;
    };
    
    // LOS ANGELES, CA
    var start = [-118.24, 33.97];
    
    // SAN FRANCISCO, CA
    var end   = [-122.41, 37.77];
    
    var dist_kilometers = haversineDistance(start, end, earth_radius['kilometers']);
    var dist_miles = haversineDistance(start, end, earth_radius['miles']);
    

    假设您已将 SQL 查询的结果集以及用户位置提供给客户端 JavaScript,您可以使用 JavaScript 原生数组排序函数中的 hasrsineDistance 函数轻松按距离对位置进行排序。

    var user_coords = [user_location.longitude, user_location.latitude];
    
    sql_results.sort(function(a, b) {
      var a_coords = [a.longitude, a.latitude];
      var b_coords = [b.longitude, b.latitude];
    
      var a_dist = haversineDistance(user_coords, a_coords, earth_radius['miles']);
      var b_dist = haversineDistance(user_coords, b_coords, earth_radius['miles'])
    
      return a_dist - b_dist;
    });
    

    【讨论】:

    • 如何使用这个脚本来处理问题?
    • 他可以根据需要使用我提供的函数在 JavaScript 中对他的结果集进行排序。
    • 我正在使用来自 phonegap 的 SQLite 用于 iOS、android 和黑莓应用程序。结果集是否以数组形式返回?如果是这样,那么我想我可以使用你的排序功能。
    【解决方案2】:

    因为你在 Javascript 中调用了你想要的函数,所以你不能使用在数据库引擎外部定义的函数作为比较运算符,特别是如果通过你提供的语法使用,它是从查询外部评估的 - 你需要数据找到值来评估数据应该返回的顺序。数据无法到达任何地方!

    相反,您可以创建一个具有额外空列的表,然后通过客户端的 JavaScript 在 HTML 中计算它。这将允许多个用户使用该应用程序,您可以在那里对其进行排序。

    当然,如果您愿意这样做,您可以在 SQLite 中创建或定义一个 C 函数 - 我不熟悉该过程,但在他们的文档 here 中有描述。这将允许您在 SQL 本身中调用它; Select *, Distance(UserLat, UserLong, places.latitude, places.longitude) as dist from places, uservalues order by dist

    或者,按照建议,您可以将数据保存回数据库,但这会限制并发性。

    最后,您可以使用 MySQL 或其他功能更全面的数据库系统。

    【讨论】:

    • 我想这是正确的答案...我不认为我可以创建一个 C 函数。所以我坚持我的建议。谢谢
    • 有时这些工具并不是工作所需要的。祝你好运!