Giter Site home page Giter Site logo

michaelsolati / geofirestore-js Goto Github PK

View Code? Open in Web Editor NEW
503.0 16.0 59.0 7.23 MB

Location-based querying and filtering using Firebase Firestore.

Home Page: https://geofirestore.com

License: MIT License

TypeScript 98.77% JavaScript 1.23%
geofire firebase firestore geolocation geohashing geofirestore geoquery hacktoberfest firebase-firestore

geofirestore-js's Introduction

geofirestore

npm npm bundle size Release CI Coveralls github GitHub stars GitHub forks

Full documentation is available at https://geofirestore.com.

GeoFirestore is an open-source library that extends the Firestore library in order to store and query documents based on their geographic location. At its heart, GeoFirestore is just a wrapper for the Firestore library, exposing many of the same functions and features of Firestore. Its main benefit, however, is the possibility of retrieving only those documents within a given geographic area - all in realtime.

GeoFirestore uses the Firebase Cloud Firestore for data storage, allowing query results to be updated in realtime as they change. GeoFirestore selectively loads only the data near certain locations, keeping your applications light and responsive, even with extremely large datasets.

GeoFirestore is designed as a lightweight add-on to Firebase. To keep things simple, GeoFirestore stores data in its own format and its own location within your Firestore database.

Table of Contents

Downloading GeoFirestore

You can install GeoFirestore via npm:

npm install geofirestore

Or you can use GeoFirestore via CDN:

<script src="https://unpkg.com/geofirestore/dist/geofirestore.js"></script>

Firebase Dependencies

If using this library in a Node.js environment, please install @google-cloud/firestore with a version >= 5.0.0 and a version < 6.0.0.

If using this library in a browser environment, please install firebase with a version >= 9.0.0 and a version < 10.0.0. Currently this library only works with the Firebase Compat library. Support for the Firebase Modular library is coming down the road.

Example Usage

Assume you are building an app to rate bars and you store all information for a bar, e.g. name, business hours and price range, and you want to add the possibility for users to search for bars in their vicinity. This is where GeoFirestore comes in. You can store each bar using GeoFirestore, using the location to build an easily queryable document. GeoFirestore then allows you to easily query which bars are nearby in a simalar fashion as geofire but will also return the bar information (not just the key or location).

Examples

You can find a full list of our demos and view the code for each of them in the examples directory of this repository. The examples cover some of the common use cases for GeoFirestore.

Documentation

Full documentation is available at https://geofirestore.com. It mostly provides the same functionality as the Firestore library, in almost the same way as the Firestore library. Many questions can be addressed by looking at the Firestore docs. However there are a few differences, and below is a little example of how to make a location based query.

import firebase from 'firebase/compat/app';
import 'firebase/compat/firestore';
import * as geofirestore from 'geofirestore';


// Initialize the Firebase SDK
firebase.initializeApp({
  // ...
});

// Create a Firestore reference
const firestore = firebase.firestore();

// Create a GeoFirestore reference
const GeoFirestore = geofirestore.initializeApp(firestore);

// Create a GeoCollection reference
const geocollection = GeoFirestore.collection('restaurants');

// Add a GeoDocument to a GeoCollection
geocollection.add({
  name: 'Geofirestore',
  score: 100,
  // The coordinates field must be a GeoPoint!
  coordinates: new firebase.firestore.GeoPoint(40.7589, -73.9851)
})

// Create a GeoQuery based on a location
const query = geocollection.near({ center: new firebase.firestore.GeoPoint(40.7589, -73.9851), radius: 1000 });

// Get query (as Promise)
query.get().then((value) => {
  // All GeoDocument returned by GeoQuery, like the GeoDocument added above
  console.log(value.docs);
});

Simple. Easy. And very similar with how Firestore handles a get from a Firestore Query. The difference being the added ability to say query near a center point, with a set radius in kilometers.

Limitations & Considerations

Compound Queries

Internally GeoFirestore creates multiple geohashes around a requested area. It then makes multiple inequality (<, <=, >, >=) queries and joins them together into one response. Unfortunately compound queries with inequalities or additional filtering methods such as orderBy, startAt and endAt are impossible with Firestore. To better understand this limitation, see the Firestore docs here.

Data Structure

Documents generated and stored in your Firestore collection by GeoFirestore are typed/structured as:

interface GeoDocumentData {
  g: {
    geohash: string;
    geopoint: GeoPoint;
  };
  [field: string]: any;
  }
  • g.geohash is the geohash generated by the library, and is required in order to make the geoqery.
  • g.geopoint is the GeoPoint used to generate the g.geohash field.

Data must be structured this way in order to work, and is why you should use the GeoFirestore library to insert data in order to be able to query it.

Security Rules

Because GeoFirestore adds the g field and expects a coordinates field, be sure to update your Firebase Security Rules to reflect the new fields. While not necessary for all applications, the rules below are an example of how you'd check for GeoFirestore specific fields.

match /collection/{key} {
  allow write: // Your previous rules here...
               && request.resource.data.g.size() == 2
               && request.resource.data.g.geohash is string
               && request.resource.data.g.geopoint is latlng
               && request.resource.data.coordinates is latlng
}

limit()

The limit filtering method is exposed through GeoFirestore, however there are some unique considerations when using it. Limits on geoqueries are applied based on the distance from the center. Geoqueries require an aggregation of queries. When performing a geoquery the library applies the limit on the client. This may mean you are loading to the client more documents then you intended. Use with this performance limitation in mind.

Contributing

All code should pass tests, as well as be well documented. Please open PRs into the dev branch. Please also see the Commit Message Guidelines for how commit messages should be structured.

geofirestore-js's People

Contributors

abeisgoat avatar dependabot[bot] avatar ebubae avatar firebase-ops avatar idanb11 avatar jacob-israel-turner avatar jamestamplin avatar jdimond avatar mauricioso avatar michaelsolati avatar mikepugh avatar mimming avatar morrislaptop avatar namanarora00 avatar nexuist avatar npmcdn-to-unpkg-bot avatar ppkavinda avatar robertdimarco avatar sararob avatar spoxies avatar startupandrew avatar stefek99 avatar zenpylon 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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

geofirestore-js's Issues

Batch method

I need to write multiple document at the same time to the database. Is there a way to use firestore batch method with this api?

e.docChanges is not a function

I keep getting the above error when I run a query. Can anyone point me in the right direction?

const geoQuery = geoFirestore.query({
center: new firebase.firestore.GeoPoint(this.state.region, this.state.region.longitude),
radius: 10.5
});

geokit?

what is geoKit in your example?

Having trouble successfully querying my data

Hi,

Sorry for the basic question, but I've been banging my head against this for the past few hours.

In the test app I set up, I have a function that adds 1000 randomly placed locations to my firestore collection within ~800km of the user:
screen shot 2018-08-22 at 11 38 58 am

Then I set up a query using geoFirestore.query(), and pass in an object containing a center GeoPoint and radius. I use .query() to turn it into a firestore query object, then execute a .get():
screen shot 2018-08-22 at 11 39 17 am

What I get back though is all 1000 locations, so for some reason the query is not returning what it should. The entire test project can be found here, and the component where all the relevant code is here.

What am I doing wrong? Thanks for your help and all the hard work going into this project!

Set an attribute to execute the query on

Hello, i really like this project for being useful, but there is something i've been stuck on and it's been a bit confusing too.

The current situation is: i connect to my collection, i make the query with range, coords and an attribute "name" to search on. What i get is an error from Firebase asking for me to create an index. The index currently sets an attribute g in ascending order to make the index. It took me some time to assume that this is the attribute used for the query (because i am really dumb reading the documentation sometimes, i'm sorry (also about the d. attribute >-<) :/)

The problem comes when i need it to query the coordinates in the documents with an attribute called coordenadas (portuguese for "coordinates").
How would i be able to use a custom attribute to query the coordinates on?

If this feature is not existent yet, i think it would be something really useful to implement.

thank you for the attention =^-^=

Problems setting GeoPoint

I was having problems with setting locations
geoFirestore.set('some_key', { coordinates: new firebase.firestore.GeoPoint(37.79, -122.41)})
giving: "Invalid GeoFire location '[object Object]': location must be an array"

using this instead solved it:
geoFirestore.set(userId, [42.497855, 27.470660])

Using:
[email protected]
[email protected]

Example request GeoFirestoreQuery

Hello! I'm trying to use this library in my Angular project, but I can't find any explicit example in the documentation, so I'm asking here if you have some time for me:
I have a "users" collection with their own documents, like name, age, date of birth and other, and I want to retrieve the users near my position. At this moment, I have a "georef" collection for every user added with:

let collectionRef = this.afs.collection('georef').ref;
let geoFirestore = new GeoFirestore(collectionRef);

geoFirestore.add({ coordinates: new firebase.firestore.GeoPoint(this.coordinates.lat, this.coordinates.lng), uid: this.globals.mySelf.uid } ).then((docRef) => { ... });

but then I don't know how to query the users near my position, I tried with geoFirestore.query(), but I don't know how to use the result GeoFirestoreQuery Object...can you please help me?

Not working on react native project

I was able to run this library in nodejs project in a console project without a problem. However, when ran it as part of a React Native project, the package and objects are loaded, however, events are not triggered when doing a query from the app running in the device.

Any guidance appreciated.

Updating an existing doc

Is there a way to continually update an existing doc with new location? I think this may be a useful feature and may be able to submit a pull request.

geoFirestore.update(key, {
           coordinates: new firebase.firestore.GeoPoint(37.79, -122.41)
       })

Feature Request : Firebase 'Functions' Compatibility and/or Observing changes to geofirestore docs

Hey Michael,

This is a bit of a two-headed question with the same goal : Do you plan on geofirestore updating its query results as document content is updated?

e.g. case:
on the backend, firebase 'functions' does some data manipulation to be updated on one to many geofirestore docs. In my client app, I want geofirestore to be able to see those updates as they occur and bring them in to the existing query results.

Obviously, this can be done with a redundant Observable of the geofirestore collection...

Another thought I had was doing a .setWithDocument() anytime firebase 'functions' needs to update the content. (Would geofirestore see this as a change?) This would seem a little more in-line with your project.

If this latter were the case, the challenge I have is in implementing geofirestore inside of 'functions'.
Unfortunately, while the constructor for geofirestore requires type "firebase.firestore.CollectionReference", firebase-admin's collection type "FirebaseFirestore.CollectionReference" isn't compatible with the constructor, nor does it seem it can be cast to the desired type...

This is getting a bit outside my knowledge-base : could an alternative constructor with the other type be easily integrated? Or do you have a thought that I could try in a fork?

Anyway, this is very much spit-balling. If I can clarify, or if this is getting way outside geofirestore's scope, shout!

Thanks.

collectionRef must be an instance of a firestore collection

I keep getting the following error messages. I'm running firebase version "version": "5.3.0". Can you please let me know what i'm doing wrong? My code is below. The error stems from the first line.

const collectionRef = firebase.firestore().collection('Locations')
const geoFirestore = new GeoFirestore(collectionRef);
const geoQuery = geoFirestore.query({
center: new firebase.firestore.GeoPoint(this.state.region.latitude, this.state.region.longitude),
radius: 10.5
});

const center = geoQuery.center();
geoQuery.on('ready', () => {
  });

geoQuery.on('key_entered', function (key, document, distance) {
  console.log(key + ' entered query at ' + document.coordinates.latitude + ',' + document.coordinates.longitude + ' (' + distance + ' km from center)');
});

geoQuery.on('key_exited', function (key, document, distance) {
  console.log(key + ' exited query to ' + document.coordinates.latitude + ',' + document.coordinates.longitude + ' (' + distance + ' km from center)');
  // removeMarker(key); // To remove a marker if you wanted
});

geoQuery.on('key_moved', function (key, document, distance) {
  console.log(key + ' moved within query to ' + document.coordinates.latitude + ',' + document.coordinates.longitude + ' (' + distance + ' km from center)');
});

geoQuery.on('key_modified', function (key, document, distance) {
  console.log(key + ' in query has been modified');
});

Returning a Collection of key, location and distance

I want to wrap your library in a google cloud function and return an array with the results to the client.

I do the following setup.

    const geoQuery = geofire.query({
        center: [parseFloat(req.query.lat), parseFloat(req.query.lon)],
        radius: parseFloat(req.query.radius)
    })

Is there any way to get the result, instead of waiting for all onKeyEnteredRegistration Events?
I need to do a response.send(results), but I Do not know which is the last item of the result set.

I had tried to put the response.send() inside the onReadyRegistration, but it happens sometimes before receiving all events in onKeyEnteredRegistration;

Any guidance appreciated.

Question about query in updateCriteria

Hello! Sorry for basic question, but can't get my code to work.

Problem: I have two ways of calling updateCriteria method, but only first one triggers updates:

  1. Updating center and distance
    onMapChange(center, radius) {
        this.geoQuery.updateCriteria({
            center: new firebase.firestore.GeoPoint(...center),
            radius: radius
        });
    }
  1. Updating query
    updateQuery() {
        this.geoQuery.updateCriteria({
            query: (ref) => ref.where('d.type', '==', this.state.type);
        });
    }

After calling onMapChange() or updateQuery() I expect documents to be filtered out, but in case of updateQuery() nothing really happens. I tried passing literally any query and by requesting this.geoQuery._query.tosString() query always changed, but documents are not changed.

Am I doing this right?

TypeError: Cannot read property 'enablePersistence' of undefined

Versions

"firebase": "^5.6.0",
"geofirestore": "^2.2.3",

Code

import * as firebase from 'firebase/app';
import 'firebase/firestore';
import { GeoFirestore } from 'geofirestore'

// Initialize the Firebase SDK
firebase.initializeApp({
  // ...
});

// Create a Firestore reference
const firestore = firebase.firestore();

// Create a GeoFirestore reference
const geofirestore = new GeoFirestore(firestore)

// Create a GeoCollection reference
const geocollection = geofirestore.collection('events')

// Create a GeoQuery based on a location
const query = geocollection.near({ center: new firestore.GeoPoint(48.1077212, 11.6019103), radius: 50 })

// Get query (as Promise)
query.get().then((value) => {
  console.log(value.docs) // All docs returned by GeoQuery
})

Console error

Uncaught TypeError: Cannot read property 'enablePersistence' of undefined
    at new e (geofirestore.js?5cdc:1)

Example

https://codesandbox.io/s/y04wj6zpoj

Is it possible to use promises instead of event listeners

According to this example code, you can perform the geo location based search.

const onKeyEnteredRegistration = geoQuery.on('key_entered', function(key, document, distance) {
  console.log(key + ' entered query at ' + document.coordinates.latitude + ',' + document.coordinates.longitude + ' (' + distance + ' km from center)');
});

Is it possible to use promises to get the same result. If so could you please give an example?

TypeError: snapshot.docChanges is not a function at...

@MichaelSolati

I get this Error with
"firebase-admin": "^6.0.0",
"geofirestore": "^2.1.1"

TypeError: snapshot.docChanges is not a function at /home/kenzdozz/WebDev/Gigasec/Node/needtest/node_modules/geofirestore/dist/index.cjs.js:925:26 at watch.onSnapshot (/home/kenzdozz/WebDev/Gigasec/Node/needtest/node_modules/@google-cloud/firestore/build/src/reference.js:1531:13) at push (/home/kenzdozz/WebDev/Gigasec/Node/needtest/node_modules/@google-cloud/firestore/build/src/watch.js:533:17) at DestroyableTransform.stream.on.proto (/home/kenzdozz/WebDev/Gigasec/Node/needtest/node_modules/@google-cloud/firestore/build/src/watch.js:560:25) at DestroyableTransform.emit (events.js:182:13) at addChunk (/home/kenzdozz/WebDev/Gigasec/Node/needtest/node_modules/through2/node_modules/readable-stream/lib/_stream_readable.js:291:12) at readableAddChunk (/home/kenzdozz/WebDev/Gigasec/Node/needtest/node_modules/through2/node_modules/readable-stream/lib/_stream_readable.js:278:11) at DestroyableTransform.Readable.push (/home/kenzdozz/WebDev/Gigasec/Node/needtest/node_modules/through2/node_modules/readable-stream/lib/_stream_readable.js:245:10) at DestroyableTransform.Transform.push (/home/kenzdozz/WebDev/Gigasec/Node/needtest/node_modules/through2/node_modules/readable-stream/lib/_stream_transform.js:148:32) at DestroyableTransform.afterTransform (/home/kenzdozz/WebDev/Gigasec/Node/needtest/node_modules/through2/node_modules/readable-stream/lib/_stream_transform.js:91:10)

You can reproduce it from this repo
https://github.com/kenzdozz/needtest

Question: Can this be used on an Express Server (node)?

Hi Michael
first up, thank you for putting together this library. I'm pretty new to coding generally, and I appreciate how much work must go into stuff like this.

I'm trying to make this library work on an express server. I've got a firestore collection of docs that have a property with GeoPoint hashes. its a toy app, so its a collection of bars (like the example use case). I want to retrieve a list of places within X kms and then render a view with the places and their data being sent to the EJS page being rendered.

Is this usecase supported? when I run the .on(key_entered, cb ) method with callback I get a couple of places but cant figure out how to get them all and then add to an array before i render the page.

All help gratefully accepted! thank you!

Bug Report: ready event fires hundreds of times for one geoQuery

I have one GeoFirestore instance and when I update the queryCriteria I get the ready event fired hundreds of times.

The documentation reads:

ready fires once when this query's initial state has been loaded from the server. The ready event will fire after all other events associated with the loaded data have been triggered. ready will fire again once each time updateCriteria() is called, after all new data is loaded and all other new events have been fired.

From this it sounds like ready should be called number of updateCriteriaCalls + 1.

But when add console.log statements to updateCriteria and to my ready event handler, I get the following:

image

Is my understanding about the ready event logic incorrect? Or is there a bug?

Feature request

Cheers for this awesome library, I have already tried it and it was awesome. I am storing the geofirestore locations on the same collection so doing a query will return me the document snapshots. Is there a way to limit the results just like in Firestore? And is there a way I would pass another Firestore query to geofirestore so that it would also order the results or sort them in a certain way using the other database fields just as we can do in Firestore.
Thanks.

Uncaught (in promise): TypeError: _this._collectionRef.orderBy is not a function > GeoFirestoreQuery.prototype._listenForNewGeohashes

Hi! I am trying to use the query like this:
... const geoFirestoreQuery = geoFirestore.query({ center: new firebase.firestore.GeoPoint(1, 2), radius: 10 });
Then I get this error:

Uncaught (in promise): TypeError: _this._collectionRef.orderBy is not a function
GeoFirestoreQuery.prototype._listenForNewGeohashes/<@http://localhost:8100/build/vendor.js:101050:34
GeoFirestoreQuery.prototype._listenForNewGeohashes@http://localhost:8100/build/vendor.js:101046:9
GeoFirestoreQuery@http://localhost:8100/build/vendor.js:100721:9
GeoFirestore.prototype.query@http://localhost:8100/build/vendor.js:100640:16
GeoFirestoreProvider@http://localhost:8100/build/main.js:1450:34
createClass@http://localhost:8100/build/vendor.js:10975:20
createProviderInstance$1@http://localhost:8100/build/vendor.js:10949:26
resolveNgModuleDep@http://localhost:8100/build/vendor.js:10934:17
NgModuleRef
.prototype.get@http://localhost:8100/build/vendor.js:12159:16
resolveDep@http://localhost:8100/build/vendor.js:12655:12
createClass@http://localhost:8100/build/vendor.js:12525:32
createDirectiveInstance@http://localhost:8100/build/vendor.js:12364:37
createViewNodes@http://localhost:8100/build/vendor.js:13802:53
createRootView@http://localhost:8100/build/vendor.js:13692:5
callWithDebugContext@http://localhost:8100/build/vendor.js:15093:39
debugCreateRootView@http://localhost:8100/build/vendor.js:14394:12
ComponentFactory
.prototype.create@http://localhost:8100/build/vendor.js:11313:37
ComponentFactoryBoundToModule.prototype.create@http://localhost:8100/build/vendor.js:4275:16
NavControllerBase.prototype._viewInit@http://localhost:8100/build/vendor.js:50655:27
NavControllerBase.prototype._nextTrns/<@http://localhost:8100/build/vendor.js:50468:17
F</l</t.prototype.invoke@http://localhost:8100/build/polyfills.js:3:14974
onInvoke@http://localhost:8100/build/vendor.js:4982:24
F</l</t.prototype.invoke@http://localhost:8100/build/polyfills.js:3:14901
F</c</r.prototype.run@http://localhost:8100/build/polyfills.js:3:10124
f/<@http://localhost:8100/build/polyfills.js:3:20240
F</l</t.prototype.invokeTask@http://localhost:8100/build/polyfills.js:3:15649
onInvokeTask@http://localhost:8100/build/vendor.js:4973:24
F</l</t.prototype.invokeTask@http://localhost:8100/build/polyfills.js:3:15562
F</c</r.prototype.runTask@http://localhost:8100/build/polyfills.js:3:10815
o@http://localhost:8100/build/polyfills.js:3:7887

Am I doing something wrong? I tried to use versions 1.2.0 and directly from the v2.0.0 branch. Thank you!

Multiple Tslint Errors

I used this library in my Firebase Function 1 month ago. It used to work until a recent npm install. I'm unable to trace which update cause the problem, but when I deploy these are the errors I get:

Module '@firebase/firestore-types' is not listed as dependency in package.json
'namespace' and 'module' are disallowed
Shadowed name: 'CollectionReference'
Shadowed name: 'DocumentChange'
Shadowed name: 'DocumentReference'
Shadowed name: 'DocumentSnapshot'
Shadowed name: 'GeoPoint'
Shadowed name: 'Query'
Shadowed name: 'QuerySnapshot'
Shadowed name: 'WriteBatch'

Cannot initiate GeoFirestore instance in node.js application

I use GeoFirestore in my node.js application. In the first lines of the document i have:
var GeoFirestore = require("geofirestore");

And then i use the code
const geoFirestore = new GeoFirestore(collectionRef);
With the collectionRef being a valid ref to the my firestore collection.

The issue is that i get the error "TypeError: GeoFirestore is not a constructor"
What is the problem here? Thanks for any help.

geoQuery.query() returns all the documents

Following code returns all the documents

const db = admin.firestore();
const collectionRef = db.collection('documents');
const geoFirestore = new GeoFirestore(collectionRef);

const geoQuery = geoFirestore.query({
    center: new admin.firestore.GeoPoint(52.1989266, 0.0499472),
    radius: 1,
});
const query = geoQuery.query();
query.get().then((querySnapshot) => {
    querySnapshot.forEach(function (doc) {
        console.log(doc.id, " => ", doc.data());
    });
});

Since the radius has been set to 1 km, it should only return the documents within that range. But this is not working as expected. Can you please let me know if the above code is correct?

ERROR: Array is not a function (evaluating 'e.docChanges()')

screenshot_2018-08-07-13-07-15

Here is my code:

 const db = firebase.firestore();
    const userCollection = db.collection('interviews');
    const geoobj = new GeoFirestore(userCollection)
    let query  = geoobj.query({
      center: coordinates,
      radius: 100,
    //  query: (ref) => ref.where('d.count', '==', 1)


    });
    query.on("ready", () => this.setState({ loading: false }));
    query.on("key_entered", (key, coords, distance) => {
      console.log("asdada",key);
    });

Cannot find namespace 'FirebaseFirestore'.

After updating to 2.1.0., the following error appears: Cannot find namespace 'FirebaseFirestore'.

I was able to fix it by changing FirebaseFirestore.CollectionReference to typesWeb.CollectionReference in the following lines:

export namespace cloud { export interface CollectionReference extends FirebaseFirestore.CollectionReference { } }

I have created PR to fix this issue. #23

Range queries

Is there a way to use range queries ('<', '<=', '>', '>=') with a document field?

Performance Slow with ~1k Markers

Hi everyone, I have ~1k markers that could be in the viewport at a time and I am seeing a bottleneck in the Chrome Performance profiler from Firestore.

I am not sure if this is due to large Geohash regions, too many updates to the underlying Firestore collection or what...

At this point, the map can get really laggy and non-responsive. (Sometimes users will get the "this tab is not responding" message...)

Has anyone dealt with similar problems / scale?

Here is what my profiler looks like:

image

Query sometimes returns no results from the same input

Hello!

Firstly, a big thanks for creating this library for Firestore. I've used the geofire library for the realtime database so it's great that it's been recreated for Firestore. Your work is much appreciated.

I've written some geohashed data to Firestore and I'm querying it using the geoFirestore.query() method. It mostly works but on some occasions it fails to trigger the key_entered event even though the query is currently hard-coded for testing.

Here's the code:
query-code

Am I missing something obvious with the way the geohashing works? I can't understand why it doesn't return the same data each time as the initial query doesn't change.

Thanks,
Marc

Firebase functions integration

Hello, I'm still struggling with this, maybe you can help,

image

When I execute 'npm run build' no matter if I comment out the firebase import, it will trigger the following error that I googled and couldn't find any specific answer, the error will only dissapear if I comment out the geofirestore import...

image

package.json

"dependencies": {
"firebase": "^5.0.4",
"firebase-admin": "~5.12.1",
"firebase-functions": "^1.0.4",
"geofirestore": "^1.2.0"
},

Unexpected attribute 'query' found in query criteria

It doesnt like query: (ref) => ref.where('d.count', '==', 1) in the following:

   geoQuery = geoFirestore.query({
      center: new firebase.firestore.GeoPoint(mapCenter.lat(), mapCenter.lng()),
      radius: radius,
      query: (ref) => ref.where('d.count', '==', 1)
    });

Has error: Unexpected attribute 'query' found in query criteria

Any thoughts?

How to update a document

Loving the library so far, just having one issue!

After using .add(), the document appears correctly in the database. On .then, the docRef is also correct. However, using .set() on the document does not seem to work - the id is not being added to the document. I may be using it incorrectly, so have attached my code.

const restaurantsGeostoreRef = db.collection('exploreMap');
const restaurantsRef = new GeoFirestore(restaurantsGeostoreRef);
export const addNewRestaurant = data =>
  restaurantsRef
    .add({
      ...data,
      coordinates: new firebase.firestore.GeoPoint(data.coordinates[1], data.coordinates[0]),
    })
    .then(docRef =>
      restaurantsRef
        .set(docRef.id, {
          id: docRef.id,
        })
        .then(() => 'Successfully added.')
        .catch(error => error),
    )
    .catch(error => error);

How can i get this to work with react native?

I'm able to get this to work with implementing this with geofire. I'd like to use Geofirestore because I'm using firestore within my application.(I figured it would be a better choice).

This works for react native.
const geofire = require('geofire');

I keep getting 'geofirestore is not a constructor' error message. Can you assist me with getting this to work in react native?

Working with 2.0

I'm trying to use version 2.0.0, but it doesn't have a "dist" folder and is therefore giving the error (Cannot find module 'geofirestore')

I don't think I can use 1.2.0 right now because it looks like it doesn't support adding additional fields to the collection (which I need)

anyway to build and publish 2.0?

Can't find variable: document

I am getting this strange issue:
whatsapp image 2018-08-20 at 1 01 33 am

"dependencies": {
"firebase": "^5.4.0",
"geofirestore": "^2.1.1",
"geolib": "^2.0.24",
"react": "16.3.1",
"react-native": "0.55.4",
"react-native-elements": "^0.19.1",
"react-native-fbsdk": "^0.7.0",
"react-native-firebase": "^4.3.8",
"react-native-google-signin": "^1.0.0-rc3",
"react-native-maps": "^0.21.0",
"react-native-material-textfield": "^0.12.0",
"react-native-navigation": "^1.1.480",
"react-native-vector-icons": "^5.0.0"
}

import firebase from 'firebase';
import 'firebase/firestore';
import { GeoFirestore } from "geofirestore";

I can't figure out how to resolve this issue. Any help would be appreciated.

Thanks

Importing GeoFirestore causes error about `self.fetch`

Adding import { GeoFirestore } from 'geofirestore' causes my react native app to crash:

undefined is not an object (evaluating 'self.fetch')

Seems like it is related with this issue, but the fix does not work for me. Has anyone run into the same problem?

Versions:

"react-native": "0.55.4",
"geofirestore": "^2.0.1",

I am using geofirestore

I am using geofirestore, that awesome. But have question.
In my app i have doc with some key-values and i need to store location for each of them.

if i am using geoFirestore.query({...}); with center and radius. Then inside key-entered i got key, doc and distance.
however as doc i got everything that stored under d key. But all my other data is stored directly inside doc, on same level as d

So i need to perform one more request to get all other data which is not very good.
Do geofirestore can give an ability to get all doc data by geoquery with center and radius ?

Thanks.

using set deletes my existing document

Hello ,
Thanks for the time you've put into this.
Before writing this I searched a lot on SO but couldn't find anything.
I may be doing something wrong but when I use geofirestore.set, it deletes the existing fields of the document and updates them with the geohas and coordinates.
My code for updation is as follows:
//uid is the userid of the user profile
geoFirestore.set(uid, { coordinates: location}).then(() => {
console.log('Provided key has been added to GeoFirestore');
}, (error) => {
console.log('Error: ' + error);
})

orderBy inside inner query doesn't work

this one works
const query = ref => ref.limit(4)
const geoQuery = geofirestore.query({ center, radius, query })

this one doesn't
const query = ref => ref.orderBy('d.createdAt', 'desc')
const geoQuery = geofirestore.query({ center, radius, query })

nothing comes through key_entered event listener
I set the indexing on firestore as it advises me to: d.createdAt DESC g ASC

Query question

Would it be possible / efficient to query based on the rectangular area of 2 geo points, instead of one and a radius? Thanks!

geofirestore__WEBPACK_IMPORTED_MODULE_5___default.a is not a constructor

Hi,

I'm getting the error geofirestore__WEBPACK_IMPORTED_MODULE_5___default.a is not a constructor

Originally seen in a nuxt app I'm working on, and reproduced in a vue cli 3 default app for testing. Also tried downgrading firebase to v5.0.3 like another person had luck with - no luck for me.

The vue cli 3 test project can be found here. The relevant code is inside the HelloWorld.vue component, here.

Thanks for your work on this library! Hopefully this is a quick fix.

Adding more fields

Guys, I am still trying to get my head around, but as I understand technically you can add more fields into stored obj?
As you are using sorting and start At and End At in filetrs, could be good to save more fields and pass more filters inside. Am I correct?

Sort by nearest without any radius

Great library, my objective is to list out the records based on the nearest to farthest based on the current location and I don't want it to limit with any radius.

how can I achieve this?

Feat: update existing document

There are some (closed) issues/questions about updating the custom 'd.' values using geoFirestore.set(). I'd like to share some of my findings, because it might save the dev's a bit of work.

Please note that I'm no JS expert...and I'm also not good at writing short and to the point

TL DR; There is no official update() function just yet, but I wrote a suggestion as inspiration that I will commit in my fork. I will not insult anyone by doing a pull/merge request, because goto: 4;.

Also @MichaelSolati said;

...in version 3.0.0 the set and update will align with how the Firestore SDK works, where you can send options for merging and what not.

The cases;
[#40] If you update only the "coordinates" on an existing document using set(), the "d." custom-fields get removed.

As @MichaelSolati said;

The set function requires a full document, so the original with modifications,

However the batch update from geoFirestore actually already uses a merge: batch.set(ref, [...], { merge: true }); so that suggests a possible work around would be to use:

geofirestore.set({ 'key': {coordinates:[..]} } )

instead of:

geofirestore.set('key', {coordinates:[..] } )

...that might work if you only update the coordinates, but even if so we would not be out of trouble yet because:

[ #45] Updating a single d.field with firestore.{set() || update()} removes other keys

If our document has multiple custom fields (d.) and you only want to update one nested d. field, then even the update() function of firestore itself might not work as expected.

db before:
{ l: '[loc]', g: 'loc_hash' d : { keyToRemain : 'staying alive', otherKey : 'leave me alone', keyToChange : 'total-make-over' } }

update:
let updateObj = {d : {keyToChange : 'new-face' }; firestore.col(ref).update(uid, updateObj);

db after:
{ l: '[loc]', g: 'loc_hash' d : { keyToChange : 'new-face' } }

However apparently if you use a source path within update() like so ['d.keyToChange'], a merge does happen.

update:
let updateObj['d.keyToChange'] = 'new-face'; firestore.col(ref).update(uid, updateObj);
db after:
{ l: '[loc]', g: 'loc_hash' d : { keyToRemain : 'staying alive', otherKey : 'leave me alone', keyToChange : 'total-make-over' } }

This 'trick' works with update() and not with, .set(ref, [...], { merge: true }); because set() needs document formed data. source.

The commit/suggestion below
adds an update() method that:

will not remove the custom d. fields
geoFirestore.update('existing_key', { coordinates: geoPoint});

will append custom keys to d.
geoFirestore.update('existing_key', { coordinates: geoPoint, keyToChange : 'new-face'});

Possible to specify document key on add?

Is there any way to specify the document key when doing geoFirestore.add()? I would like to listen for changes on the created document (i.e. doing onSnapshot on it) and I would like to use the user's id as the key to ensure that every user has only one corresponding document in the geo collection.

Get all documents within a radius

Trying to retrieve all the documents that fall within the radius of a certain point.

Query:

const geoQuery = geoFirestore.query({
    center: new firebase.firestore.GeoPoint(51.5074, 0.1278),
    radius: 5,
  });

  geoQuery
    .query()
    .get()
    .then(querySnapshot => {
      querySnapshot.forEach(doc => {
        console.log(doc.data());
      });
    })

Firestore (documents set by geofirestore.set():
Document 1 (same as search point):

coordinates: [51.5074, 0.1278]

Document 2:

coordinates: [41.1537, -8.612549]

No matter what I try, it is always returning both results, even though they are 100's of kms away from eachother. Can someone please recommend what I can do to make this work?

Much appreciated! :)

key_exited fires after ready event

Hi,

I'm listening for documents with a fixed query that won't change. But when I remove a document that affects the query results, "ready" event gets fired before "key_exited".

Is that the right behaviour?

Undefined is not a function (near ...snapshot.docChanges.forEach...)

Not sure why I'm getting this error, but here's my code:

const eventsRef = firebase.firestore().collection("events");
const locationsRef = firebase.firestore().collection("locations");
const geoFirestore = new GeoFirestore(locationsRef);
const query = geoFirestore.query({
    center: [this.state.region.latitude, this.state.region.longitude],
    radius: 1
});
query.on("ready", () => this.setState({ loading: false }));
query.on("key_entered", (key, coords, distance) => {
     console.log(key);
});

Both locations and events collections exist in my database, and I'm able to add new items without hassle:

const eventsRef = firebase.firestore().collection("events");
const locationsRef = firebase.firestore().collection("locations");
const geoFirestore = new GeoFirestore(locationsRef);
try {
      let docRef = await eventsRef.add({
        name: this.state.eventName,
        location: new firebase.firestore.GeoPoint(latitude, longitude),
        owner: `/users/${firebase.auth().currentUser.uid}`
     });
     await geoFirestore.set(docRef.id, [latitude, longitude]);
    } 
catch (err) {
    console.log(err);
    this.setState({
        loading: false
    });
    Alert.alert("Error", "Sorry, there was an error creating your event.");
}

According to the redbox the error is located around line 385 in query.js. I'm guessing this is related to the newer firebase package (5.0.1) that asks you to put this piece of code before anything else:

// Avoid deprecation warning
firebase.firestore().settings({
    timestampsInSnapshots: true
});

Kind of in a damned if I do and damned if I don't situation here; since not including that makes firebase crash my app and including it makes geofirestore crash my app!

Any suggestions?

Slow Performance on 360k Records - Running as Node.js function

I'm using geofirestore in a firestore cloud function with an http endpoint to perform radius search - return records within the radius of a lat/lon coordinate.

This query runs against a document collection with 360k records.

The performance is quite slow - queries are taking 12-14 seconds according to the Cloud Functions log. In comparison, I created a small Cloud SQL Postgres database and Express.js web API and it’s returning identical queries in 300ms.

I have one composite index created, otherwise it’s using default setting. The composite index I created is: "d.locationType ASC g ASC".

Below is a screenshot of the document structure. I added a few child fields in the 'd' field created by Geofirestore.

I posted this question on the [email protected] discussion group, and one of the Firestore engineers suggested reaching out to you - but would be willing to talk with the geofirestore developers and possibly help. I'll point him to this issue.

Any guidance on how to optimize this to run - ideally <1 sec?

image

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.