嵌套 Firestore 集合上的 Firestore 地理查询

Firestore geoquery on nested firestore collection

学习教程https://firebase.google.com/docs/firestore/solutions/geoqueries https://www.youtube.com/watch?v=mx1mMdHBi5Q 我创建了我的数据库设计,看起来像

当我查询任何位置时,我总是得到 0 个结果,然后我尝试查询非嵌套集合(如教程视频 https://www.youtube.com/watch?v=mx1mMdHBi5Q 中所示),然后我得到了结果。

我的非嵌套集合设计如下:

嵌套集合的代码(这是我的要求,但不起作用)

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()+"");
                }
            });
}

非嵌套集合代码(有效)

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()+"");
                }
            });
}

此查询永远不会 return 任何结果:

Query q = db.collection("Owners").document().collection("Ghars")
        .orderBy("geohash")
        .startAt(b.startHash)
        .endAt(b.endHash);

当您在不带任何参数的情况下调用 document() 时,您正在创建对新的、不存在的文档 的引用。所以它的 Ghars 子集合也不存在,你的查询也得不到结果。


如果您想查询特定所有者的 Ghars 子集合,您应该在调用 document():

时指定所有者的文档 ID
                                        // 
Query q = db.collection("Owners").document(ownerDocId).collection("Ghars")
        .orderBy("geohash")
        .startAt(b.startHash)
        .endAt(b.endHash);

如果您想查询所有 Ghars 个子集合,您可以 use a collection group query,它会查询具有特定名称的所有集合:

                   // 
Query q = db.collectionGroup("Ghars")
        .orderBy("geohash")
        .startAt(b.startHash)
        .endAt(b.endHash);