Git Product home page Git Product logo

geo-nearby's Introduction

geo-nearby License npm

Build Status node Test Coverage bitHound Score

Note: This module stores all data in memory - remember that.

Uber fast nearby locations search by coordinates.

Supports Array, Object, JSON and GeoJSON as input data.

Usage

$ npm install geo-nearby --save
const Geo = require('geo-nearby');

const dataSet = [
  { i: 'Perth',     g: 3149853951719405 },
  { i: 'Adelaide',  g: 3243323516150966 },
  { i: 'Melbourne', g: 3244523307653507 },
  { i: 'Canberra',  g: 3251896081369449 },
  { i: 'Sydney',    g: 3252342838034651 },
  { i: 'Brisbane',  g: 3270013708086451 },
  { i: 'Sydney',    g: 3252342838034651 }
];

const geo = new Geo(dataSet);

geo.nearBy(-33.87, 151.2, 5000); // 5000 - 5km

In g stored geohash with 52-bit precision.

If you want to change property name, you can do that with options:

const Geo = require('geo-nearby');

const dataSet = [
  { id: 1, name: 'Perth',     geoHash: 3149853951719405 },
  { id: 2, name: 'Adelaide',  geoHash: 3243323516150966 },
  { id: 3, name: 'Melbourne', geoHash: 3244523307653507 },
  { id: 4, name: 'Canberra',  geoHash: 3251896081369449 },
  { id: 5, name: 'Sydney',    geoHash: 3252342838034651 },
  { id: 6, name: 'Brisbane',  geoHash: 3270013708086451 },
  { id: 7, name: 'Sydney',    geoHash: 3252342838034651 }
];

const geo = new Geo(dataSet, { hash: 'geoHash' });

geo.nearBy(-33.87, 151.2, 5000);

Data set

For best performance it is recommended to use the default data set syntax:

const dataSet = [
  ...
  { i: <id>, g: <geo hash> },
  { i: <id>, g: <geo hash> },
  ...
];

You can use a createCompactSet method for creating a data set with recommended syntax of your data:

const data = [
  [-35.30278, 149.14167, 'Canberra'],
  [-33.86944, 151.20833, 'Sydney'],
  [-37.82056, 144.96139, 'Melbourne'],
  [-34.93333, 138.58333, 'Adelaide'],
  [-27.46778, 153.02778, 'Brisbane'],
  [-31.95306, 115.85889, 'Perth']
];

const dataSet = Geo.createCompactSet(data);
const geo = new Geo(dataSet, { sorted: true });

geo.nearBy(-33.87, 151.2, 5000);

createCompactSet supports Array, parsed and unparsed JSON, parsed and unparsed GeoJSON as input data:

const data = {
  type: 'FeatureCollection',
  features: [
    { type: 'Feature', geometry: { type: 'Point', coordinates: [44, 64] }, properties: { name: 'Arkhangelskaya Oblast' } },
    { type: 'Feature', geometry: { type: 'Point', coordinates: [40.5433, 64.5401] }, properties: { name: 'Arkhangelsk' } },
    { type: 'Feature', geometry: { type: 'Point', coordinates: [39.8302, 64.5635] }, properties: { name: 'Severodvinsk' } },
    { type: 'Feature', geometry: { type: 'Point', coordinates: [40.8122, 64.4165] }, properties: { name: 'Novodvinsk' } },
    { type: 'Feature', geometry: { type: 'Point', coordinates: [46.64963, 61.25745] }, properties: { name: 'Kotlas' } }
  ]
};

const dataSet = Geo.createCompactSet(data, { id: 'name' });
const geo = new Geo(dataSet, { sorted: true });

geo.nearBy(64.54, 40.54, 5000);

You also can change default values for a createCompactSet method if your data looks different:

const data = [
  { _id: 1000, name: 'Arkhangel’skaya Oblast’', country: 'RU', coord: { lon: 44, lat: 64 }, admin1: 'Arkhangelskaya' },
  { _id: 1001, name: 'Arkhangelsk', country: 'RU', coord: { lon: 40.5433, lat: 64.5401 }, admin1: 'Arkhangelskaya' },
  { _id: 1002, name: 'Severodvinsk', country: 'RU', coord: { lon: 39.8302, lat: 64.5635 }, admin1: 'Arkhangelskaya' },
  { _id: 1003, name: 'Novodvinsk', country: 'RU', coord: { lon: 40.8122, lat: 64.4165 }, admin1: 'Arkhangelskaya' },
  { _id: 1004, name: 'Kotlas', country: 'RU', coord: { lon: 46.64963, lat: 61.25745 }, admin1: 'Arkhangelskaya' }
];

const dataSet = Geo.createCompactSet(data, { id: '_id', lat: ['coord', 'lat'], lon: ['coord', 'lon'] });
const geo = new Geo(dataSet, { sorted: true });

geo.nearBy(64.54, 40.54, 5000);

You can specify setOptions property in constructor options, it will create data set automatically, but it may take lots of time for large data:

const data = [
  { lat: -35.30278, lon: 149.14167, name: 'Canberra' },
  { lat: -33.86944, lon: 151.20833, name: 'Sydney' },
  { lat: -37.82056, lon: 144.96139, name: 'Melbourne' },
  { lat: -34.93333, lon: 138.58333, name: 'Adelaide' },
  { lat: -27.46778, lon: 153.02778, name: 'Brisbane' },
  { lat: -31.95306, lon: 115.85889, name: 'Perth' }
];

const geo = new Geo(data, { setOptions: { id: 'name', lat: 'lat', lon: 'lon' } });

geo.nearBy(-33.87, 151.2, 5000);

If you have a huge data it may be more wisely save them to file:

const data = require('./huge.data.set.file.json');

Geo.createCompactSet({ id: '_id', lat: 'lat', lon: 'lon', file: './compact.set.json' });

And then load in variable:

const dataSet = require('./compact.set.json');
const geo = new Geo(dataSet, { sorted: true });

geo.nearBy(64.54, 40.54, 5000);

Advanced usage

Limiting results

For limiting results, you have two ways:

1. Define limit in the options. That allows you to define a permanent limit for results.

const geo = new Geo(dataSet, { limit: 1 });

geo.nearBy(64.54, 40.54, 3000);
new Geo(dataSet, { limit: 1 }).nearBy(64.54, 40.54, 3000);
geo.nearBy(-33.87, 151.2, 5000);

In all these cases, the results will be limited to 1.

2. Define limit by limit() method. That allows you to define a temporary limit for results.

const foo = new Geo(dataSet).limit(1);
foo.nearBy(64.54, 40.54, 5000); //up to 1
foo.nearBy(64.54, 40.54, 5000); //no limits

const bar = new Geo(dataSet, { limit: 1 }).limit(10);
bar.nearBy(64.54, 40.54, 5000); //up to 10
bar.nearBy(64.54, 40.54, 5000); //up to 1. Options limit - permanent limit.
bar.limit(2).nearBy(64.54, 40.54, 5000); //up to 2

A range of distances

For a more precise definition, you can use a range of distances. It's a bit slower but more accurate.

const geo = new Geo(dataSet);
geo.limit(2).nearBy(64.54, 40.54, [250, 30000]);

Note: Don't use too small distance for start value. For values, less than 250 script execution may take too much time for unsorted data set. 250 - 500 is usually sufficient.

Binary search

If you created data set by createCompactSet method or your own data set is sorted by geohash property in ascending order, you can activate extremely fast binary search.

Just set sorted property as true in constructor options.

A binary search is 20 times faster than normal.

const geo = new Geo(dataSet, { sorted: true });
geo.limit(1).nearBy(64.54, 40.54, [250, 30000]);

Sorting data

If you have data set (with recommended syntax) which is unsorted, you can easily sort it, just set sort property as true in constructor options.

Data set will be automatically sorted using fast introsort algorithm. But keep in mind, sorting will take some time.

In some case, search in unsorted data set will be faster than sort and search.

const geo = new Geo(dataSet, { sort: true });
geo.limit(1).nearBy(64.54, 40.54, [250, 30000]);

Methods

new Geo(dataSet, [options])

Constructor.

Params:

  • dataSet (String|Array|Object) - Data set (JSON, GeoJSON, etc)
  • [options] (Object) - Options:
    • hash (String) - Key path (by default = 'g')
    • limit (Integer) - Limit results (by default no limits)
    • sort (Boolean) - Will sort data set with introsort algorithm
    • sorted (Boolean) - If data set is sorted in ascending order, set sorted as true it will enable binary search (uber fast mode)
    • setOptions (Object) - Options from createCompactSet:
      • hash (String|Array) - Key (name|path) (by default inherits hash from above)
      • id (String|Array) - Key (name|path) (by default = 2)
      • lat (String|Array) - Key (name|path) (by default = 0)
      • lon (String|Array) - Key (name|path) (by default = 1)
      • file (String) - File path to save
const geo = new Geo(dataSet, { hash: 'geo', limit: 1, sorted: true });

.nearBy(lat, lon, distance)

Search method of nearby places.

Params:

  • lat (Float) - Latitude
  • lon (Float) - Longitude
  • distance (Integer|Array) - Distance in meters
const geo = new Geo(dataSet);
geo.nearBy(64.54, 40.54, [500, 300000]);

.limit([limit])

Temporary limit for results.

Params:

  • [limit] (Integer) - Limit results (by default no limits)
const geo = new Geo(dataSet);
geo.limit(1).nearBy(64.54, 40.54, [500, 300000]);

.createCompactSet(dataSet, [options])

Method creates data set.

Static method.

Params:

  • dataSet (String|Array|Object) - Data set (JSON, GeoJSON, etc)
  • [options] (Object) - Options:
    • hash (String|Array) - Key (name|path)
    • id (String|Array) - Key (name|path) (by default = 2)
    • lat (String|Array) - Key (name|path) (by default = 0)
    • lon (String|Array) - Key (name|path) (by default = 1)
    • file (String) - File path to save
const dataSet = Geo.createCompactSet(data, { id: ['names', 'name', 'id'] });

License

The MIT License (MIT)
Copyright (c) 2015-2016 Alexey Bystrov

geo-nearby's People

Contributors

strikeentco avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

geo-nearby's Issues

Geo result with full dataset

Hi,

Currently i am just getting id and geohash as result.
If i want to get full dataset along with id and deohash then is it possible with geo-nearby?

i am getting as search result:

 [
  {
"i": "AABC",
"g": 3624733589598182
},
  {
"i": "123dgff",
"g": 3624733589598182
}
]

I want something like:

 [
  {
"i": "AABC",
"g": 3624733589598182,
"name" : "test",
"model" : "aa11"
},
  {
"i": "123dgff",
"g": 3624733589598182,
"name" : "123",
"model" : "aa22"
}
]

Bug in nearBy() calculation?

I was seeing search results being included that were way outside the search radius, so I wrote the following code:

    const db = GeoNearby.createCompactSet( [ [ 40, 90, 'abc' ] ] );
    console.log(db);
    const gnb = new GeoNearby(db);
    const res = gnb.nearBy(45, 95, 390620);
    console.log(res);

This code returns the single result. The issue is that these two points are actually 690000m apart, and so the result set should be empty!

The value 390620 is the minimum value that works. Anything lower and the result set is empty.

Using an array as the search radius makes no difference in the behavior. [250, 390620] is still the minimum value.

Get nearBy lat lon

It would be great to have the option to return lat lon instead of geoHash,

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.