Issue
Following the tutorial https://firebase.google.com/docs/firestore/solutions/geoqueries and https://www.youtube.com/watch?v=mx1mMdHBi5Q i've created my database design which looks like
When I'm querying for any location I'm always getting 0 result, then I tried querying non nested collection (as shown in tutorial video https://www.youtube.com/watch?v=mx1mMdHBi5Q) then I'm getting the result.
My non nested collection design looks like:
Code for nested collection (which is my requirement and doesn't work)
public void queryHashes() {
// Find cities within 50km of London
final GeoLocation center = new GeoLocation(19.912524, 76.079626);
final double radiusInM = 50 * 1000;
// Each item in 'bounds' represents a startAt/endAt pair. We have to issue
// a separate query for each pair. There can be up to 9 pairs of bounds
// depending on overlap, but in most cases there are 4.
List<GeoQueryBounds> bounds = GeoFireUtils.getGeoHashQueryBounds(center, radiusInM);
final List<Task<QuerySnapshot>> tasks = new ArrayList<>();
for (GeoQueryBounds b : bounds) {
Query q = db.collection("Owners").document().collection("Ghars")
.orderBy("geohash")
.startAt(b.startHash)
.endAt(b.endHash);
tasks.add(q.get());
}
// Collect all the query results together into a single list
Tasks.whenAllComplete(tasks)
.addOnCompleteListener(new OnCompleteListener<List<Task<?>>>() {
@Override
public void onComplete(@NonNull Task<List<Task<?>>> t) {
List<DocumentSnapshot> matchingDocs = new ArrayList<>();
for (Task<QuerySnapshot> task : tasks) {
QuerySnapshot snap = task.getResult();
for (DocumentSnapshot doc : snap.getDocuments()) {
double lat = doc.getDouble("lat");
double lng = doc.getDouble("lng");
// We have to filter out a few false positives due to GeoHash
// accuracy, but most will match
GeoLocation docLocation = new GeoLocation(lat, lng);
double distanceInM = GeoFireUtils.getDistanceBetween(docLocation, center);
if (distanceInM <= radiusInM) {
matchingDocs.add(doc);
}
}
}
// matchingDocs contains the results
// ...
Log.v("matchingDocsD", matchingDocs.size()+"");
}
});
}
Code for non-nested collection (which works)
public void queryHashes() {
// Find cities within 50km of London
final GeoLocation center = new GeoLocation(19.912524, 76.079626);
final double radiusInM = 50 * 1000;
// Each item in 'bounds' represents a startAt/endAt pair. We have to issue
// a separate query for each pair. There can be up to 9 pairs of bounds
// depending on overlap, but in most cases there are 4.
List<GeoQueryBounds> bounds = GeoFireUtils.getGeoHashQueryBounds(center, radiusInM);
final List<Task<QuerySnapshot>> tasks = new ArrayList<>();
for (GeoQueryBounds b : bounds) {
Query q = db.collection("10K")
.orderBy("geohash")
.startAt(b.startHash)
.endAt(b.endHash);
tasks.add(q.get());
}
// Collect all the query results together into a single list
Tasks.whenAllComplete(tasks)
.addOnCompleteListener(new OnCompleteListener<List<Task<?>>>() {
@Override
public void onComplete(@NonNull Task<List<Task<?>>> t) {
List<DocumentSnapshot> matchingDocs = new ArrayList<>();
for (Task<QuerySnapshot> task : tasks) {
QuerySnapshot snap = task.getResult();
for (DocumentSnapshot doc : snap.getDocuments()) {
double lat = doc.getDouble("lat");
double lng = doc.getDouble("lng");
// We have to filter out a few false positives due to GeoHash
// accuracy, but most will match
GeoLocation docLocation = new GeoLocation(lat, lng);
double distanceInM = GeoFireUtils.getDistanceBetween(docLocation, center);
if (distanceInM <= radiusInM) {
matchingDocs.add(doc);
}
}
}
// matchingDocs contains the results
// ...
Log.v("matchingDocsD", matchingDocs.size()+"");
}
});
}
Solution
This query will never return any results:
Query q = db.collection("Owners").document().collection("Ghars")
.orderBy("geohash")
.startAt(b.startHash)
.endAt(b.endHash);
When you call document()
without any arguments, you're creating a reference to a new, non-existing document. So its Ghars
subcollection won't exist either, and your query gets no results.
If you want to query a specific owner's Ghars
subcollection, you should specify the owner's document ID in the call to document()
:
// 👇
Query q = db.collection("Owners").document(ownerDocId).collection("Ghars")
.orderBy("geohash")
.startAt(b.startHash)
.endAt(b.endHash);
If you want to query across all Ghars
subcollections, you can use a collection group query, which queries all collections with a specific name:
// 👇
Query q = db.collectionGroup("Ghars")
.orderBy("geohash")
.startAt(b.startHash)
.endAt(b.endHash);
Answered By - Frank van Puffelen
Answer Checked By - Marie Seifert (JavaFixing Admin)