node.js中的地理编码工具

node.js中的地理编码工具,node.js,geocoding,geo,Node.js,Geocoding,Geo,我正在寻找用于处理地理空间数据的node.js库。我在数据库中有一大组地理标记数据 期望的功能包括: 地理编码和反向地理编码 查找附近的物品 查找地质范围内的项目 就像RoR中相当于GeoCoder gem的节点一样 对于地理编码和反向部分,您可以使用 对于查找部分,最好的方法是使用您的数据库系统,如果它支持地理操作的话 如果没有,可能会将您的数据库复制到另一个数据库(使用地理操作)?如果您需要处理千兆字节的数据,而不是很容易加载内存中的所有内容,那么数据库就是这样存在的:)。在自己尝试回答这个

我正在寻找用于处理地理空间数据的node.js库。我在数据库中有一大组地理标记数据

期望的功能包括:

  • 地理编码和反向地理编码
  • 查找附近的物品
  • 查找地质范围内的项目

  • 就像RoR中相当于GeoCoder gem的节点一样

    对于地理编码和反向部分,您可以使用

    对于查找部分,最好的方法是使用您的数据库系统,如果它支持地理操作的话


    如果没有,可能会将您的数据库复制到另一个数据库(使用地理操作)?如果您需要处理千兆字节的数据,而不是很容易加载内存中的所有内容,那么数据库就是这样存在的:)。

    在自己尝试回答这个问题时发现了这个问题,我将更新它

    上面推荐的库最近一次更新是在2014年,似乎没有涉及承诺。正在积极维护,它基于承诺的api允许您在使用Babel/ES7时执行以下操作:

    const NodeGeocoder = require('node-geocoder');
    let geocoder = NodeGeocoder()
    let assert = require('assert');
    
    describe('geocoder#geocode()', () => {
    
        it('geocodes things', async () => {
          let result = await geocoder.geocode("Ottawa, Canada")
          assert.equal(45.4215296, result[0].latitude)
        })
    
    })
    
    我确实发现NodeGeocoder给出了它从Google/whomever获得的结果的一个子集,Ruby的geocoder项目似乎给出了整个响应

    //result returned from geocoder.geocode:
    [ { formattedAddress: 'Ottawa, ON, Canada',
        latitude: 45.4215296,
        longitude: -75.69719309999999,
        extra: 
         { googlePlaceId: 'ChIJrxNRX7IFzkwR7RXdMeFRaoo',
           confidence: 0.5,
           premise: null,
           subpremise: null,
           neighborhood: null,
           establishment: null },
        administrativeLevels: 
         { level2long: 'Ottawa Division',
           level2short: 'Ottawa Division',
           level1long: 'Ontario',
           level1short: 'ON' },
        city: 'Ottawa',
        country: 'Canada',
        countryCode: 'CA',
        provider: 'google' } ]
    
    根据lat/lng查找数据将由数据库负责。我一直在使用,它们在_RECTANGLE中有一个函数
    ,这是对您使用的
    map.getBounds()
    的完美补充。以下是一个例子:

    export async function locationsWithinBounds(swLat, swLng, neLat, neLng) {
      let query = aqlQuery`
        RETURN WITHIN_RECTANGLE(vertices, ${swLat}, ${swLng}, ${neLat}, ${neLng})
      `
      let results = await db.query(query)
      let allResults = await results.all()
      return allResults[0]
    }
    
    如果你探索他们的另一半,你会发现类似于
    附近的
    是在多边形中的

    如果您需要在浏览器中使用地理功能,您应该查看。

    根据您的应用程序的不同,如果您索引的内容不是直接的地理编码/rev地理编码API,则某种形式的地理哈希可能会有所帮助

    Geohash的一种类型是,它可以用一个64位整数,以一个指尖到地球表面的精度对区域进行索引

    下面是一个查找某物是否位于检索时WITHO(1)运行时的边界中的示例。在本例中,它检查是否有人在布鲁克林的威廉斯堡:

    const s2 = require('@radarlabs/s2');
    
    const williamsburgLongLats = [
      [-73.95841598510742, 40.72423412682422],
      [-73.96957397460938, 40.71226430831242],
      [-73.9683723449707, 40.70497727808752],
      [-73.96184921264648, 40.69951148213175],
      [-73.95923137664795, 40.70852329864894],
      [-73.94775152206421, 40.70391994183744],
      [-73.94163608551025, 40.71145106322093],
      [-73.94335269927979, 40.71834706657437],
      [-73.9469575881958, 40.719778223045275],
      [-73.94970417022705, 40.722217623379684],
      [-73.95056247711182, 40.721892375167045],
      [-73.95193576812744, 40.72335597960796],
      [-73.95425319671631, 40.72312830991985],
    ];
    
    const lls = williamsburgLongLats.map((lnglat) => {
      const [lng, lat] = lnglat;
      return new s2.LatLng(lat, lng);
    });
    
    const s2Level = 14; // ~0.32 km^2
    const neighborhoodS2Cells =
      new Set(s2.RegionCoverer.getCoveringTokens(
        lls,
        { min: s2Level, max: s2Level }
      ));
    
    const user1LongLat = [-73.95429611206055, 40.71369559554873]; // in williamsburg
    const user2LongLat = [-73.9266586303711, 40.71616774648679];  // not in williamsburg
    
    const user1S2 = new s2.CellId(new s2.LatLng(user1LongLat[1], user1LongLat[0])).parent(14); // level 14 to ensure 1:1 mapping to cover
    const user2S2 = new s2.CellId(new s2.LatLng(user2LongLat[1], user2LongLat[0])).parent(14); // level 14 to ensure 1:1 mapping to cover
    
    console.log(neighborhoodS2Cells.has(user1S2.token())); // true - O(1)
    console.log(neighborhoodS2Cells.has(user2S2.token())); // false - O(1)
    
    
    const s2 = require('@radarlabs/s2');
    
    const williamsburgLongLats = [
      [-73.95841598510742, 40.72423412682422],
      [-73.96957397460938, 40.71226430831242],
      [-73.9683723449707, 40.70497727808752],
      [-73.96184921264648, 40.69951148213175],
      [-73.95923137664795, 40.70852329864894],
      [-73.94775152206421, 40.70391994183744],
      [-73.94163608551025, 40.71145106322093],
      [-73.94335269927979, 40.71834706657437],
      [-73.9469575881958, 40.719778223045275],
      [-73.94970417022705, 40.722217623379684],
      [-73.95056247711182, 40.721892375167045],
      [-73.95193576812744, 40.72335597960796],
      [-73.95425319671631, 40.72312830991985],
    ];
    
    const lls = williamsburgLongLats.map((lnglat) => {
      const [lng, lat] = lnglat;
      return new s2.LatLng(lat, lng);
    });
    
    const s2Level = 14; // ~0.32 km^2
    const neighborhoodS2Cells =
      new Set(s2.RegionCoverer.getCoveringTokens(
        lls,
        { min: s2Level, max: s2Level }
      ));
    
    const user1LongLat = [-73.95429611206055, 40.71369559554873]; // in williamsburg
    const user2LongLat = [-73.9266586303711, 40.71616774648679];  // not in williamsburg
    
    const user1S2 = new s2.CellId(new s2.LatLng(user1LongLat[1], user1LongLat[0])).parent(14); // level 14 to ensure 1:1 mapping to cover
    const user2S2 = new s2.CellId(new s2.LatLng(user2LongLat[1], user2LongLat[0])).parent(14); // level 14 to ensure 1:1 mapping to cover
    
    console.log(neighborhoodS2Cells.has(user1S2.token())); // true - O(1)
    console.log(neighborhoodS2Cells.has(user2S2.token())); // false - O(1)