MichaelSolati / geofirestore-js

Location-based querying and filtering using Firebase Firestore.
https://geofirestore.com
MIT License
504 stars 58 forks source link

React Native: r._query.orderBy is not a function #124

Closed QuintonC closed 5 years ago

QuintonC commented 5 years ago

I'm attempting to query data given a lat/long and continue to get the red screen of shame in React Native.

Version information: Firebase: ^5.11.1 GeoFirestore: ^3.3.1

Here is my implementation:

import * as firebase from 'firebase';
import 'firebase/firestore';
import { GeoCollectionReference, GeoFirestore, GeoQuery, GeoQuerySnapshot } from 'geofirestore';

const geoFirestore = new GeoFirestore(firebase.firestore()); 
const geoCollection = new GeoCollectionReference(geoFirestore.collection('PrayerRequests'));

...

const query = new GeoQuery(geoCollection.near({
    center: new firebase.firestore.GeoPoint(latitude, longitude),
    radius: this.state.distance
}));

query.get().then((value: GeoQuerySnapshot) => {

    console.log(value.docs);

});

...

Here is the result (terminal output below)...

Image of Error

- node_modules/geofirestore/dist/geofirestore.js:1:15708 in <unknown>
* [native code]:null in map
- node_modules/geofirestore/dist/geofirestore.js:1:14819 in get
- node_modules/geofirestore/dist/geofirestore.js:1:15077 in get
* components/PrayerRequests.js:89:24 in <unknown>
- node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js:7004:16 in callCallback
- node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js:7048:19 in commitUpdateEffects
- node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js:7036:22 in commitUpdateQueue
- node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js:12165:10 in commitLifeCycles
- node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js:13496:8 in commitAllLifeCycles
- node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js:92:15 in invokeGuardedCallbackImpl
- node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js:306:36 in invokeGuardedCallback
- node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js:13702:8 in commitRoot
- node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js:15269:13 in completeRoot
- node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js:15197:21 in performWorkOnRoot
- node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js:15090:24 in performWork
- node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js:15047:14 in performSyncWork
- node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js:14925:19 in requestWork
- node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js:14711:16 in scheduleWork
- node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js:7700:17 in enqueueSetState
- node_modules/react/cjs/react.development.js:364:31 in setState
* components/PrayerRequests.js:78:34 in <unknown>
- node_modules/expo-location/build/Location.js:275:16 in _getCurrentPositionAsyncWrapper$
- node_modules/regenerator-runtime/runtime.js:45:44 in tryCatch
- node_modules/regenerator-runtime/runtime.js:271:30 in invoke
- node_modules/regenerator-runtime/runtime.js:45:44 in tryCatch
- node_modules/regenerator-runtime/runtime.js:135:28 in invoke
- node_modules/regenerator-runtime/runtime.js:145:19 in <unknown>
- node_modules/promise/setimmediate/core.js:37:14 in tryCallOne
- node_modules/promise/setimmediate/core.js:123:25 in <unknown>
- node_modules/react-native/Libraries/Core/Timers/JSTimers.js:152:14 in _callTimer
- node_modules/react-native/Libraries/Core/Timers/JSTimers.js:200:17 in _callImmediatesPass
- node_modules/react-native/Libraries/Core/Timers/JSTimers.js:464:30 in callImmediates
* [native code]:null in callImmediates
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:320:6 in __callImmediates
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:135:6 in <unknown>
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:297:10 in __guard
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:134:17 in flushedQueue
* [native code]:null in flushedQueue
* [native code]:null in invokeCallbackAndReturnFlushedQueue
QuintonC commented 5 years ago

Err, apparently I was way off the beaten path here..

Changed over to the following...

const prayer_ref = firebase.firestore().collection('PrayerRequests');
const geoFirestore = new GeoFirestore(prayer_ref); 

navigator.geolocation.getCurrentPosition((position) => {

    latitude = position.coords.latitude;
    longitude = position.coords.longitude;

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

    let results = [];

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

    // Remove documents when they fall out of the query
    geoQuery.on('key_exited', ($key) => {

        console.log('Key Exited');

        const index = results.findIndex((place) => place.$key === $key);
        if (index >= 0) results.splice(index, 1);
    });

    // As documents come in, add the $key/id to them and push them into our results
    geoQuery.on('key_entered', ($key, result) => {

        console.log('Key Entered');

        result.$key = $key;
        results.push(result);
    });

No more red screen, but it seems that my query is not firing? I'm not getting any results into my results array or anything for the keys entering/exiting. Have I done something wrong?

MichaelSolati commented 5 years ago

So you're using the syntax of 2.x.x, you were closer with your first sample for 3.x.x. But let me help you (I think I know what you're doing wrong)

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

// Geofirestore reference
const geoFirestore = new GeoFirestore(firebase.firestore());
// Here you created a GeoCollectionReference from a GeoCollectionReference, totally
// unnecessary and incompatible, the collection method on a GeoFirestore object
// returns a GeoCollectionReference, you only need to use a GeoCollectionReference
// if you pass into it a regular collection reference...
const geoCollection = geoFirestore.collection('PrayerRequests');

...
// Similar to your GeoCollectionReference, you only pass a standard query to the GeoQuery
// not a GeoQuery or a GeoCollectionReference (which extends a GeoQuery)
const query = geoCollection.near({
    center: new firebase.firestore.GeoPoint(latitude, longitude),
    radius: this.state.distance
});

// I think this should work now
query.get().then((value) => {

    console.log(value.docs);

});
QuintonC commented 5 years ago

@MichaelSolati That definitely helped. I'm still not exactly getting the results that I am looking for.

It fires now, and it definitely cleared things up a bit...

I have the radius set to 500, I'm assuming this is miles (maybe it's kilometers by default), but still, 500 is more than enough for me to be getting at least five results from my collection.

I have two records in my collection which have a Location/Geopoint of [37.785834° N, 122.406417° W]

I have my device lat/long values set as 37.785834 and -122.406417 respectively. The one thing I notice here is the longitudinal value in Firestore does not have a negative until I open the GeoPoint up. Is this normal?

MichaelSolati commented 5 years ago

So the library uses KM, so it'll be 500km (which will be a bit smaller than miles). As far as how firebase displays GeoPoint objects it usually shows it in the console with NESW and when you open the object you then get the negative or positive numbers.

I'd also recommend trying a larger radius and check your documents distance, it's included in the QueryDocumentSnapshot if you iterate over the docs. Hopefully looking at them will help you see if the distances make sense.

QuintonC commented 5 years ago

@MichaelSolati I'm still not certain that this is working as intended... even setting with an absurdly high distance and querying with the proper latitude/longitude, I am still not getting any docs in my promise. I set it to 250000 just for test purposes and still received nothing. Took it a step further and set it to 511000000 km and still received nothing in return.

Something is just not right with the way that data is being gathered. It gathers data just fine when querying without geoFirestore.

I've got the code implemented as you have it a few comments up and this is what I get in console (logging value instead of value.docs)

D {
  "_center": GeoPoint {
    "_lat": 37.785834,
    "_long": -122.406417,
  },
  "_docs": Array [],
  "_querySnapshot": Object {
    "docChanges": [Function docChanges],
    "docs": Array [],
  },
}
MichaelSolati commented 5 years ago

Can I see a sample of how your data is stored in firestore?

QuintonC commented 5 years ago

@MichaelSolati Let me know if this helps. I've been combing through the docs and haven't found anything that particularly sticks out to me as being incorrect... Another issue I know I'm going to face is parsing through this data.

The idea is that we are displaying this data newest to oldest with the ability of users to set the filter for distanced-based results. If you have any suggestions on how to make that work with this those would be much appreciated.

Imgur

MichaelSolati commented 5 years ago

So geofirestore requires data to be structured in a certain way in order to work, check this out -> https://github.com/geofirestore/geofirestore-js/tree/v3.3.1#data-structure