{"_id":"@artieworld/geofirex","_rev":"3-5d8d4048b486797566c7a0cdaccbb4a9","name":"@artieworld/geofirex","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.0":{"name":"@artieworld/geofirex","version":"0.1.0","description":"Realtime Firestore GeoQueries with RxJS","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","repository":{"type":"git","url":"https://github.com/codediodeio/geofirex.git"},"scripts":{"test":"jest --coverage --forceExit --runInBand","test:watch":"jest --watchAll","build":"rollup -c","dev":"rollup -c -w","publish":""},"keywords":["rxjs","firebase","geofire","geohash","map","firestore"],"contributors":[{"name":"Dylan Golow","url":"https://github.com/dylangolow"}],"author":{"name":"Jeff Delaney"},"license":"ISC","peerDependencies":{"firebase":"^7.2.0","rxjs":"^6.2.1"},"devDependencies":{"@firebase/firestore-types":"^0.4.3","@turf/bearing":"^6.0.1","@turf/distance":"^6.0.1","@turf/turf":"^5.1.6","@types/chance":"^1.0.1","@types/faker":"^4.1.2","@types/geojson":"^7946.0.4","@types/jest":"^23.3.14","@types/lodash":"^4.14.110","@types/ngeohash":"^0.6.1","@types/turf":"^3.5.32","firebase":"^7.2.3","jest":"^24.9.0","lodash":"^4.17.10","rollup":"^1.26.3","rollup-plugin-analyzer":"^2.0.4","rollup-plugin-bundle-size":"^1.0.3","rollup-plugin-commonjs":"9.1.0","rollup-plugin-node-resolve":"3.3.0","rollup-plugin-sizes":"^0.4.2","rollup-plugin-typescript2":"0.12.0","rollup-plugin-uglify":"^3.0.0","rxjs":"^6.2.1","ts-jest":"^24.1.0","ts-lint":"^4.5.1","ts-loader":"^6.2.1","ts-node":"^8.4.1","tslib":"^1.10.0","tslint":"5.9.1","typescript":"^3.7.2"},"_id":"@artieworld/geofirex@0.1.0","dist":{"shasum":"2d7dbbecf7efd50b38f1efee3792bc36b89befbc","integrity":"sha512-JhTIaDRVXBDA8emEM6FHEP4vCfagRUCz/JOI/gAdHolfiD7E+VEtOljqeKSjVK8eRgI+ZQEuEQnw3pWT858xmw==","tarball":"https://registry.npmjs.org/@artieworld/geofirex/-/geofirex-0.1.0.tgz","fileCount":3,"unpackedSize":9319,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg4LsQCRA9TVsSAnZWagAASesP/2CBKQwb1Nw0+ByTai+Z\njgUq3lk3acd6kydTKlbVV6nD+9YhgBaDTYpxDTUM1t8lm+JeIV8jLEWqJUMD\nVhO754m/XkxB6pCEL1hCi8u0Fb7nnPBNMouEsRI5KRMwK2s/ZC47vIHb1egL\nPX8DQ62dAO2SnrwjEb9JlfWvHu1Lv2SuTkmlCKPMOFzwRmM1WSDIDZfqq20/\ndGhXjtYOPPZWpkxEbZGEXZpqkuML0OquhIihRoZw9wKvLBkZPaS+HxdyNEII\nnKs47FvR/jIPSxQdJDAXIqhYDvORsNir2HgfDtbvfedLPIAJQgxbhlsuM7EO\nH6He0hM8+Arpqzw0g7wtG2COC9iBhtPEN+LkFggj0HPxVmnxN8Is2twzm/CJ\n9t6GSeyjBf4DBC8Nn2W3GrEW3YX8wro7UP/Gtt9uLDgZ9GWJbWtzXkQvS3tQ\n8IntpOgf/0+sD1aiUPZb+eyLUzPHNspnHSq6mCQ5esgxfuBt4M61jZHsrjQn\nTZiGgD+K+9XV24frJnyzg1XXEa6p+7EZexitK+u86qxEevWapa1rEgljfRQ4\nUjpVko11GggRCR0+obFXhkayOiBExAjHwTEQvXHz5Eq1tFsMCxFsnc7xQJ6b\nbHlBwFKQDyEFH3K0HiVJisA72x8OAAIzjv17S9WglfiGMjVVvJzS08Gtpdos\nEMIQ\r\n=WTYs\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDeWNyIxPtflXuYwlzitWqV+pZl7njNS4w9hsJyzZzdagIhAKzzmGH7a0ZnzyrCHVq3Obm/crC6G5h80W61cUqFU19L"}]},"_npmUser":{"name":"dylangolow","email":"dylangolow@gmail.com"},"directories":{},"maintainers":[{"name":"dylangolow","email":"dylangolow@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/geofirex_0.1.0_1625340688359_0.9732930858072273"},"_hasShrinkwrap":false},"0.1.1":{"name":"@artieworld/geofirex","version":"0.1.1","description":"Realtime Firestore GeoQueries with RxJS","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","repository":{"type":"git","url":"https://github.com/codediodeio/geofirex.git"},"scripts":{"test":"jest --coverage --forceExit --runInBand","test:watch":"jest --watchAll","build":"rollup -c","dev":"rollup -c -w","publish":""},"keywords":["rxjs","firebase","geofire","geohash","map","firestore"],"contributors":[{"name":"Dylan Golow","url":"https://github.com/dylangolow"}],"author":{"name":"Jeff Delaney"},"license":"ISC","peerDependencies":{"firebase":"^7.2.0","rxjs":"^6.2.1"},"devDependencies":{"@firebase/firestore-types":"^0.4.3","@turf/bearing":"^6.0.1","@turf/distance":"^6.0.1","@turf/turf":"^5.1.6","@types/chance":"^1.0.1","@types/faker":"^4.1.2","@types/geojson":"^7946.0.4","@types/jest":"^23.3.14","@types/lodash":"^4.14.110","@types/ngeohash":"^0.6.1","@types/turf":"^3.5.32","firebase":"^7.2.3","jest":"^24.9.0","lodash":"^4.17.10","rollup":"^1.26.3","rollup-plugin-analyzer":"^2.0.4","rollup-plugin-bundle-size":"^1.0.3","rollup-plugin-commonjs":"9.1.0","rollup-plugin-node-resolve":"3.3.0","rollup-plugin-sizes":"^0.4.2","rollup-plugin-typescript2":"0.12.0","rollup-plugin-uglify":"^3.0.0","rxjs":"^6.2.1","ts-jest":"^24.1.0","ts-lint":"^4.5.1","ts-loader":"^6.2.1","ts-node":"^8.4.1","tslib":"^1.10.0","tslint":"5.9.1","typescript":"^3.7.2"},"_id":"@artieworld/geofirex@0.1.1","dist":{"shasum":"6e739247f256096ac0bd2de2f3149d54e0cfe7b6","integrity":"sha512-bAursnKRX9WPEyCM0OupjgLUfNEy8Xu8plpr3ZZUzEJHmLvBSv2UQeFDLxpq8X+dMMJ+XVnUVp6vf55bbTFClw==","tarball":"https://registry.npmjs.org/@artieworld/geofirex/-/geofirex-0.1.1.tgz","fileCount":11,"unpackedSize":68884,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg4L1yCRA9TVsSAnZWagAAFpAP/3Ckqacuo05ETLS+6wlc\nWNcbSvJI4PyEhjT9sxd1x++yOibjhFDAwZ5uKep2CvMeByHGKZtzAkQnXhr9\nBWAaJBPTTPvNcll7vIfnTIwhDL1YM/fDb6pd9vKNLtPXDGsu1QecmlVEWhYW\ny368mSjD41fAupikbDAvHCczko4TvlKjGpAirvvhJICgfMggaYaNVaAeiRWK\nxMl53EACjBVXynaxdOH6cscT5+QUtzkSl67Aa7yfOJoj9D4iBmIH7DJITcwL\nHgRZC+CFZtiNlhl1PIzZ/fRRLi+06EwZTznnKm8gSkc8zSfo0SVZwWCVp3Ao\nCE4W5KcXNxYBecp62JuLmyRf3x/rjlCUe9iQxMwt9ecHWo5z36bS9KsbHd/T\nHGm4lavUSw1GLIbD4ntWLjMXZZFW6DWPY10ti3tlpHemb8q/r243owhy3Wuv\nT9He1ddnBZs9sH60Otc2jelsrGuDKpMJ9uxo1feZzf1qoinil4HWgZjTvXZe\nlGA8CQdJMqsVf87sR/NHy093P/VKWj8VPWpvaFBprahBih06ZxnWZm6GUbnq\nLyVBYlD7CZcWeEGXF+vAVYs0V7PYs9oV4R9iLT0qOK3dPBBUR32NuJ2YGFl7\nH3+gZ+Ck/6oZRqtO0mTTv0eM94u111uq19rCX40Z/LKcvqKXRUwx1VucRqbf\nqRKn\r\n=EbGO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDwANstQa7A9lhkzdY+5WfnMe7ASn5TPLwXYmEsusOchgIhAOnKzev8NHNjQOItc7L/r4EjKzQIHKawofuoK/WiZiR8"}]},"_npmUser":{"name":"dylangolow","email":"dylangolow@gmail.com"},"directories":{},"maintainers":[{"name":"dylangolow","email":"dylangolow@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/geofirex_0.1.1_1625341298211_0.7015643856171971"},"_hasShrinkwrap":false},"0.1.2":{"name":"@artieworld/geofirex","version":"0.1.2","description":"Realtime Firestore GeoQueries with RxJS","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","repository":{"type":"git","url":"https://github.com/codediodeio/geofirex.git"},"scripts":{"test":"jest --coverage --forceExit --runInBand","test:watch":"jest --watchAll","build":"rollup -c","dev":"rollup -c -w","publish":""},"keywords":["rxjs","firebase","geofire","geohash","map","firestore"],"author":{"name":"Jeff Delaney"},"license":"ISC","peerDependencies":{"firebase":"^8.3.2","rxjs":"^6.6.7"},"devDependencies":{"@firebase/firestore-types":"^0.4.3","@turf/bearing":"^6.0.1","@turf/distance":"^6.0.1","@turf/turf":"^5.1.6","@types/chance":"^1.0.1","@types/faker":"^4.1.2","@types/geojson":"^7946.0.4","@types/jest":"^23.3.14","@types/lodash":"^4.14.110","@types/ngeohash":"^0.6.1","@types/turf":"^3.5.32","firebase":"^7.2.3","jest":"^24.9.0","lodash":"^4.17.10","rollup":"^1.26.3","rollup-plugin-analyzer":"^2.0.4","rollup-plugin-bundle-size":"^1.0.3","rollup-plugin-commonjs":"9.1.0","rollup-plugin-node-resolve":"3.3.0","rollup-plugin-sizes":"^0.4.2","rollup-plugin-typescript2":"0.12.0","rollup-plugin-uglify":"^3.0.0","rxjs":"^6.2.1","ts-jest":"^24.1.0","ts-lint":"^4.5.1","ts-loader":"^6.2.1","ts-node":"^8.4.1","tslib":"^1.10.0","tslint":"5.9.1","typescript":"^3.7.2"},"_id":"@artieworld/geofirex@0.1.2","dist":{"shasum":"3423cf29a688d1dcc3d3bbd9583ecfd8de6f3694","integrity":"sha512-nhZIDnHlhM8wNqdF6iGzQOEysNq0IdoIfJeLNLRE8X9PDtcMXG4XfKM9u2XOarjWnluDEx8ZnvCb9rX/RyAMsg==","tarball":"https://registry.npmjs.org/@artieworld/geofirex/-/geofirex-0.1.2.tgz","fileCount":11,"unpackedSize":68938,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg4MCQCRA9TVsSAnZWagAAFdEP/ihnJ5kFnMmxvsTEqa2v\neUeTAMxTkFEWn67mjyeT1V3nzlA6GWnN3/uaZL5FSUIzs0o01WVvy0VReyzP\n3VouYSTQ3pRR6Qp1+8i05Uz9gt2bo6cz7wdTxRflhf4EXJeY4h7LC7kD97vY\nL0VpsYhVuzgY5/n9Yrn6/t10NnLGuRpY+SlvdVhBVD25/xDvfbna3y96xJLL\n2pkKbVXHqGZ2SVdQC999rwpebmsbJDLFzgLW8OIhe7xwnHQ10Vbo2ZusmK57\nidxZhPkBQkSWVGV6iVLLi2dkYvrGVaJvfbYDRjpaqp8gDRD+cC/bqV81+ePC\n26zOW6mdLPq5CBKH/x1HdTuCdsZJAAvQ/hvKC1mQ/joyZ62kKJgv3Bw9chEW\nBGQ7T7Zc6umNpTUYnM15ixuW9krOBnHAKM87/AOVbO3ZaAXonzlAnE1lSvyi\nZ82JDh6zxkGz8L68nhfba9uytRsuRwW3/RppgC11OkAJdvZXEwdripMTOxjJ\nB3tyM7quAg6JypbNdCiwMUYbmrGT3J+HcMGXlcq/cKOgGU52+jDBjcHiLyi4\ni2Tr4bunQuiC8mBQ9oISqw6lmvP/xldOkuUbFGaJeb3TCvO/sLuX/Rc6QfbP\nBDR/qYCQrzK1OamqvqmlVV/r7BOZMTd0YjqlngVTVIuFs2kyRqUIVV41XYXi\nohog\r\n=ekpc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDduu+Xa+U42WVxWS2Lokm3p1RCKIyyL4V896JTfovkZQIgR66dfKfQOYfFPoR3CqYxn+AUY83+UZPl1jyzW3Z7v4M="}]},"_npmUser":{"name":"dylangolow","email":"dylangolow@gmail.com"},"directories":{},"maintainers":[{"name":"dylangolow","email":"dylangolow@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/geofirex_0.1.2_1625342096318_0.15379972825988042"},"_hasShrinkwrap":false}},"time":{"created":"2021-07-03T19:31:28.013Z","0.1.0":"2021-07-03T19:31:28.458Z","modified":"2022-04-04T15:38:36.579Z","0.1.1":"2021-07-03T19:41:38.351Z","0.1.2":"2021-07-03T19:54:56.422Z"},"maintainers":[{"name":"dylangolow","email":"dylangolow@gmail.com"}],"description":"Realtime Firestore GeoQueries with RxJS","keywords":["rxjs","firebase","geofire","geohash","map","firestore"],"repository":{"type":"git","url":"https://github.com/codediodeio/geofirex.git"},"author":{"name":"Jeff Delaney"},"license":"ISC","readme":"<p align=\"center\">\n\n<a href=\"https://slackin-pbfjhfxnsa.now.sh\"><img src=\"https://slackin-pbfjhfxnsa.now.sh/badge.svg\"></a>\n\n<a href=\"https://circleci.com/gh/codediodeio/geofirex\"><img src=\"https://circleci.com/gh/codediodeio/geofirex.svg?style=svg\"></a>\n\n</p>\n\n# GeoFireX\n\nRealtime Geolocation with Firestore & RxJS. Query geographic points within a radius on the web or Node.js. \n\n- :point_right: [Live Demo](https://geo-test-c92e4.firebaseapp.com)\n- :tv: [Video Tutorial](https://angularfirebase.com/lessons/geolocation-query-in-firestore-realtime/)\n\n## :zap: QuickStart\n\n```shell\nnpm install geofirex rxjs firebase\n```\n\n### Initialize\n\nThe library is a lightweight extension for the Firebase Web and Admin JavaScript SDKs to provide tools for wrangling geolocation data in Firestore.\n\nWeb:\n\n```js\n// Init Firebase\nimport firebase from 'firebase/app';\nfirebase.initializeApp(yourConfig);\n\n// Init GeoFireX\nimport geofirex from 'geofirex';\nconst geo = geofirex.init(firebase);\n```\n\nNode.js with the Firebase Admin SDK:\n\n```js\nconst admin = require('firebase-admin');\nadmin.initializeApp();\n\nconst geo = require('geofirex').init(admin);\n```\n\nWith Typescript:\n\n```ts\nimport * as geofirex from 'geofirex'; \nconst geo = geofirex.init(firebase);\n```\n\n### Write Geolocation Data\n\nNext, add some geolocation data in your database using the main Firebase SDK. You can add multiple points to a single doc. Calling `geo.point(lat, lng)` creates an object with a [geohash string](https://www.movable-type.co.uk/scripts/geohash.html) and a [Firestore GeoPoint](https://firebase.google.com/docs/reference/android/com/google/firebase/firestore/GeoPoint). Data must be saved in this format to be queried.\n\n```ts\nconst cities = firestore().collection('cities');\n\nconst position = geo.point(40, -119);\n\ncities.add({ name: 'Phoenix', position });\n```\n\n\n![](https://firebasestorage.googleapis.com/v0/b/geo-test-c92e4.appspot.com/o/point1.png?alt=media&token=0c833700-3dbd-476a-99a9-41c1143dbe97)\n\n### Query Geo Data\n\nQuery Firestore for _cities.position within 100km radius of a centerpoint_.\n\n```ts\nconst center = geo.point(40.1, -119.1);\nconst radius = 100;\nconst field = 'position';\n\nconst query = geo.query(cities).within(center, radius, field);\n```\n\nEach hit returns a realtime Observable of the document data, plus some useful `hitMetadata` like _distance_ and _bearing_ from the query centerpoint.\n\n```ts\nquery.subscribe(console.log);\n// [{ ...documentData, hitMetadata: { distance: 1.23232, bearing: 230.23 }  }]\n```\n\nYou now have a realtime stream of data to visualize on a map.\n\n![](https://firebasestorage.googleapis.com/v0/b/geo-test-c92e4.appspot.com/o/geoquery-fire2.gif?alt=media&token=487abd17-90a3-4589-a82d-81d172ddeb25)\n\n## :notebook: API\n\n### `query<T>(ref: CollectionReference | Query | string): GeoFireQuery<T>`\n\nCreates reference to a Firestore collection or query that can be used to make geo-queries.\n\nExample:\n\n```ts\nconst geoRef = geo.query('cities');\n\n// OR make a geoquery on top of a firestore query\n\nconst firestoreRef = firestore().collection('cities').where('name', '==', 'Phoenix');\nconst geoRef = geo.query(firestoreRef);\n```\n\n#### `within(center: FirePoint, radius: number, field: string): Observable<T[]>`\n\n```js\nconst query = geoRef.within(center: FirePoint, radius: number, field: string)\n        \nquery.subscribe(hits => console.log(hits))\n\n// OR fetch as a promise\n\nimport { get } from 'geofirex';\n\nconst hits = await get(query);\n```\n\nQuery the parent Firestore collection by geographic distance. It will return documents that exist within X kilometers of the centerpoint.\n\nEach doc also contains returns _distance_ and _bearing_ calculated on the query on the `hitMetadata` property.\n\n\n\n### `point(latitude: number, longitude: number): FirePoint`\n\nReturns an object with the required geohash format to save to Firestore. \n\nExample: `const point = geo.point(38, -119)`\n\nA point is a plain JS object with two properties.\n\n- `point.geohash` Returns a geohash string at precision 9\n- `point.geopoint` Returns a Firestore GeoPoint \n\n\n## Additional Features\n\nThe goal of this package is to facilitate rapid feature development with tools like MapBox, Google Maps, and D3.js. If you have an idea for a useful feature, open an issue.\n\n### Logging\n\nEach query runs on a set of geohash squares, so you may read more documents than actually exist inside the radius. Use the `log` option to examine the total query size and latency.\n\n```js\nquery.within(center, radius, field, { log: true })\n```\n\n![Logging GeoQueries](https://firebasestorage.googleapis.com/v0/b/geo-test-c92e4.appspot.com/o/geofirex-logging.PNG?alt=media&token=9b8b487d-18b2-4e5f-bb04-564fa6f2996d)\n\n### Geo Calculations\n\nConvenience methods for calculating distance and bearing. \n\n- `geo.distance(geo.point(38, -118), geo.point(40, -115))` Haversine distance \n- `geo.bearing(to, from)` Haversine bearing \n\n### `toGeoJSON` Operator\n\nA custom RxJS operator that transforms a collection into a [GeoJSON FeatureCollection](https://macwright.org/2015/03/23/geojson-second-bite.html#featurecollection). Very useful for tools like [MapBox](https://blog.mapbox.com/real-time-maps-for-live-events-fad0b334e4e) that can use GeoJSON to update a realtime data source.\n\n```ts\nimport { toGeoJSON } from 'geofirex';\n\nconst query = geo.query('cars').within(...)\n\nquery.pipe( toGeoJSON() )\n\n// Emits a single object typed as a FeatureCollection<Geometry>\n{\n  \"type\": \"FeatureCollection\",\n  \"features\": [...]\n}\n```\n\n#### Promises with `get`\n\nDon't need a realtime stream? Convert any query observable to a promise by wrapping it with `get`.\n\n```ts\nimport { get } from 'geofirex';\n\nasync function getCars {\n    const query = geo.query('cars').within(...)\n    const cars = await get(query)\n}\n```\n\n## Tips\n\n### Compound Queries\n\nThe only well-supported type of compound query is `where`. A geoquery combines multiple smaller queries into a unified radius, so  `limit` and pagination operators will not provide predictable results - a better approach is to search a smaller radius and do your sorting client-side. \n\n\nExample:\n\n```ts\n// Make a query like you normally would\nconst users = firestore().collection('users').where('status', '==', 'online');\n\n\nconst nearbyOnlineUsers = geo.query(users).within(center, radius, field);\n```\n\nNote: This query requires a composite index, which you will be prompted to create with an error from Firestore on the first request.\n\n\n### Usage with RxJS < 6.2, or Ionic v3\n\nThis package requires RxJS 6.2, but you can still use it with older versions without blowing up your app by installing rxjs-compat.\n\nExample:\n\n```shell\nnpm i rxjs@latest rxjs-compat\n```\n\n### Make Dynamic Queries the RxJS Way\n\n```ts\nconst radius = new BehaviorSubject(1);\nconst cities = geo.query('cities');\n\nconst points = this.radius.pipe(\n  switchMap(rad => {\n    return cities.within(center, rad, 'point');\n  })\n);\n\n// Now update your query\nradius.next(23);\n```\n\n### Always Order by `[Latitude, Longitude]`\n\nThe GeoJSON spec formats coords as `[Longitude, Latitude]` to represent an X/Y plane. However, the Firebase GeoPoint uses `[Latitude, Longitude]`. For consistency, this library always requires to use the latter Firebase-style format.\n","readmeFilename":"README.md"}