• Stars
    star
    460
  • Rank 95,202 (Top 2 %)
  • Language
    TypeScript
  • Created over 6 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

🌐 πŸ“ Geolocation Queries with Firestore & RxJS

GeoFireX

Realtime Geolocation with Firestore & RxJS. Query geographic points within a radius on the web or Node.js.

⚑ QuickStart

npm install geofirex rxjs firebase

Initialize

The library is a lightweight extension for the Firebase Web and Admin JavaScript SDKs to provide tools for wrangling geolocation data in Firestore.

Web:

// Init Firebase
import firebase from 'firebase/app';
firebase.initializeApp(yourConfig);

// Init GeoFireX
import geofirex from 'geofirex';
const geo = geofirex.init(firebase);

Node.js with the Firebase Admin SDK:

const admin = require('firebase-admin');
admin.initializeApp();

const geo = require('geofirex').init(admin);

With Typescript:

import * as geofirex from 'geofirex'; 
const geo = geofirex.init(firebase);

Write Geolocation Data

Next, 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 and a Firestore GeoPoint. Data must be saved in this format to be queried.

const cities = firestore().collection('cities');

const position = geo.point(40, -119);

cities.add({ name: 'Phoenix', position });

Query Geo Data

Query Firestore for cities.position within 100km radius of a centerpoint.

const center = geo.point(40.1, -119.1);
const radius = 100;
const field = 'position';

const query = geo.query(cities).within(center, radius, field);

Each hit returns a realtime Observable of the document data, plus some useful hitMetadata like distance and bearing from the query centerpoint.

query.subscribe(console.log);
// [{ ...documentData, hitMetadata: { distance: 1.23232, bearing: 230.23 }  }]

You now have a realtime stream of data to visualize on a map.

πŸ““ API

query<T>(ref: CollectionReference | Query | string): GeoFireQuery<T>

Creates reference to a Firestore collection or query that can be used to make geo-queries.

Example:

const geoRef = geo.query('cities');

// OR make a geoquery on top of a firestore query

const firestoreRef = firestore().collection('cities').where('name', '==', 'Phoenix');
const geoRef = geo.query(firestoreRef);

within(center: FirePoint, radius: number, field: string): Observable<T[]>

const query = geoRef.within(center: FirePoint, radius: number, field: string)
        
query.subscribe(hits => console.log(hits))

// OR fetch as a promise

import { get } from 'geofirex';

const hits = await get(query);

Query the parent Firestore collection by geographic distance. It will return documents that exist within X kilometers of the centerpoint.

Each doc also contains returns distance and bearing calculated on the query on the hitMetadata property.

point(latitude: number, longitude: number): FirePoint

Returns an object with the required geohash format to save to Firestore.

Example: const point = geo.point(38, -119)

A point is a plain JS object with two properties.

  • point.geohash Returns a geohash string at precision 9
  • point.geopoint Returns a Firestore GeoPoint

Additional Features

The 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.

Logging

Each 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.

query.within(center, radius, field, { log: true })

Logging GeoQueries

Geo Calculations

Convenience methods for calculating distance and bearing.

  • geo.distance(geo.point(38, -118), geo.point(40, -115)) Haversine distance
  • geo.bearing(to, from) Haversine bearing

toGeoJSON Operator

A custom RxJS operator that transforms a collection into a GeoJSON FeatureCollection. Very useful for tools like MapBox that can use GeoJSON to update a realtime data source.

import { toGeoJSON } from 'geofirex';

const query = geo.query('cars').within(...)

query.pipe( toGeoJSON() )

// Emits a single object typed as a FeatureCollection<Geometry>
{
  "type": "FeatureCollection",
  "features": [...]
}

Promises with get

Don't need a realtime stream? Convert any query observable to a promise by wrapping it with get.

import { get } from 'geofirex';

async function getCars {
    const query = geo.query('cars').within(...)
    const cars = await get(query)
}

Tips

Compound Queries

The 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.

Example:

// Make a query like you normally would
const users = firestore().collection('users').where('status', '==', 'online');


const nearbyOnlineUsers = geo.query(users).within(center, radius, field);

Note: This query requires a composite index, which you will be prompted to create with an error from Firestore on the first request.

Usage with RxJS < 6.2, or Ionic v3

This package requires RxJS 6.2, but you can still use it with older versions without blowing up your app by installing rxjs-compat.

Example:

npm i rxjs@latest rxjs-compat

Make Dynamic Queries the RxJS Way

const radius = new BehaviorSubject(1);
const cities = geo.query('cities');

const points = this.radius.pipe(
  switchMap(rad => {
    return cities.within(center, rad, 'point');
  })
);

// Now update your query
radius.next(23);

Always Order by [Latitude, Longitude]

The 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.

More Repositories

1

sveltefire

Cybernetically enhanced Firebase apps
Svelte
955
star
2

angular-firestarter

🍱 πŸ”₯ Angular + Firebase Progressive Web App Starter
TypeScript
931
star
3

rektor-db

Rektor Vector Database
588
star
4

code-this-not-that-js

JavaScript Pro Tips - Code This, Not That
JavaScript
512
star
5

firestore-migrator

πŸš„ A CLI utility for moving data to and from Cloud Firestore
TypeScript
311
star
6

async-await-pro-tips

TypeScript
232
star
7

electron-forge-svelte

A starter template for Electron Forge + Svelte 3
JavaScript
132
star
8

gimmie-sticker

Trade a Pull Request for a Sticker
JavaScript
123
star
9

ngrx-vs-ngxs

A side-by-side comparison of Angular state management libraries
TypeScript
116
star
10

cloud-functions-master-course

Firebase Cloud Functions Master Course
HTML
113
star
11

ngrx-fire

Demo app using Angular + ngrx + Firebase
TypeScript
109
star
12

angular-gtag

πŸ”– Google Analytics gtag.js for Angular
TypeScript
108
star
13

angular-firebase-stripe

Full Stack Stripe Payments Solution with Angular + Firebase
TypeScript
88
star
14

ionic4-master-course

Source Code for the Ionic 4 Master Course
TypeScript
67
star
15

sveltefire-template

App template for SvelteFire
HTML
52
star
16

ionic-firestarter

Ionic Firebase Starter Template
TypeScript
44
star
17

stripe-firebase-master-course

44
star
18

hnpwa-angular5

Hacker News PWA with an Angular 5 Service Worker
HTML
42
star
19

vue-firestore-hello-world

Quickstart using Webpack, Vuefire, and Firestore
JavaScript
23
star
20

magic-music-flutter-create

Dart
19
star
21

can-i-use-ng-add

Where can I use the `ng add` command?
16
star
22

hippicons

an alternative icon font for the web
HTML
13
star
23

flowmap

Stream and slice data
Dart
13
star
24

javascript-jeopardy

A Realtime Trivia Game
HTML
12
star
25

lazy-loading-angular

A bare minimum demo for Component Lazy Loading in Angular 4
TypeScript
11
star
26

lex-chatbot-lambda

Python validation for Lex. AWS Chatbot Hackathon 2017
Python
10
star
27

self-driving-car-projects

Self Driving Car Projects
Jupyter Notebook
10
star
28

machine-learning-nanodegree

Machine learning projects and examples
HTML
10
star
29

tasksnail

Rails, AJAX, and Devise - Single Page Application Demo
CSS
9
star
30

hotroute

TypeScript
8
star
31

anchorage

Community Powered Cruising Guide for Boaters
JavaScript
7
star
32

lightstate

Experimental StatefulObject
TypeScript
5
star
33

firestarter-geofire

TypeScript
5
star
34

nice-tweets-only

Sentiment Validation with Ionic v4 + Cloud Language API + Cloud Functions
TypeScript
5
star
35

icon-font-lesson

codediode.io lesson for creating custom icon fonts
CSS
4
star
36

brachial-plexus-ultrasound-segmentation

Neural network comparison for Kaggle Ultrasound Segmentation competition
Jupyter Notebook
3
star
37

rembg-webapp-tutorial

a simple webapp with rembg
HTML
3
star
38

kaggle-scripts

Data visualization and machine learning scripts on Kaggle
Jupyter Notebook
3
star
39

juicesherpa

Build Juice Recipes with Realtime Nutrition Facts
Ruby
2
star
40

platform

A digital sandbox of Matthew harwood
TypeScript
2
star