【问题标题】:Firebase Location QueryFirebase 位置查询
【发布时间】:2016-10-26 21:08:59
【问题描述】:

我正在使用 Firebase 在 android 上设计一个基于位置的餐厅搜索应用程序。 firebase 上的餐厅类如下;

 restaurants
-key
  address: "NYC"
  city: "New York"
  description: ""
  id: 60000
  latitude: 39.895107
  longitude: 32.797819
  name: "Pizza Store"

片段类

mainActivity.mDatabase.child("restaurants").addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot snapshot) {
            System.out.println("There are " + snapshot.getChildrenCount() + " restaurans");
            for (DataSnapshot postSnapshot : snapshot.getChildren()) {
                Restaurant post = postSnapshot.getValue(Restaurant.class);
                mapmap2.put(post.getName(), postSnapshot.getKey());
                restaurants.add(post);
            }
            adapter = new RestaurantCardViewAdapter(getActivity(), restaurants, MapListFragment.this);
            mRecyclerView.setAdapter(adapter);
        }

        @Override
        public void onCancelled(DatabaseError firebaseError) {
            System.out.println("The read failed: " + firebaseError.getMessage());
        }
    });

现在,我可以列出所有餐厅。但我想查询用户位置。首先,我想列出用户位置附近的 20 家餐厅,当用户加载页面时,我想获得下 20 家最近的餐厅。我在互联网上进行了一些搜索。我找到了 GeoFire 库,但据我了解,它可以与旧版 firebase 一起使用。如何使用这些条件进行查询?

【问题讨论】:

    标签: android firebase location firebase-realtime-database


    【解决方案1】:

    Firebase 查询只能按单个属性进行过滤/排序。由于位置由经度和纬度组成,因此在您现在的格式中,您无法根据位置进行查询。

    幸运的是,有一个名为 GeoFire 的附加库。该库将经度和纬度组合成一个名为geohash 的属性。基于此属性,它可以按到给定位置的距离进行过滤。

    我建议您查看 Geofire,看看它是否适合您的用例。

    【讨论】:

    • 感谢您的出色回答。我搜索了 GeoFire 的属性。但我有一些疑问。建议将位置条目与餐厅分开。输入带有餐厅 ID 的位置信息和对该位置根的查询。就像在这个链接中一样,stackoverflow.com/questions/38340949/…。但我不明白,当我查询位置时,我会得到最近的餐厅钥匙。在那之后,我必须用这些钥匙拿到这些餐馆。怎么办啊,那不是数据库很贵吗?
    • 实际上不是。由于使用了 geohashes,GeoFire 通常需要读取比返回更多的位置数据。通过让您单独查找附加信息,您实际上可能会使用更少的带宽。而且它并不像您想象的那么慢,因为 Firebase 通过现有连接将请求传输到管道上。见stackoverflow.com/questions/35931526/…
    【解决方案2】:

    我在答案的帮助下解决了这个问题。我为名为“restaurant_locations”的 geofire 推了一个单独的孩子。我在插入餐厅时分别推送位置。

          GeoFire geoFire;
          String itemId = mDatabase.child("restaurants").push().getKey();
          mDatabase.child("restaurants").child(itemId).setValue(restaurant);
    
          geoFire = new GeoFire(mDatabase.child("restaurants_location"));
          geoFire.setLocation(itemId, new GeoLocation(Double.valueOf(rd.location.latitude), Double.valueOf(rd.location.longitude)));
    

    然后,当我需要通过位置查询时,我使用了 geofire 查询。

        geoFire = new GeoFire(mDatabase.child("restaurants_location"));
        GeoQuery geoQuery = geoFire.queryAtLocation(new GeoLocation(39.896263, 32.799652), 1);
    
        geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
            @Override
            public void onKeyEntered(String key, GeoLocation location) {
                System.out.println(String.format("Key %s entered the search area at [%f,%f]", key, location.latitude, location.longitude));
                mDatabase.child("restaurants").child(key).addValueEventListener(new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot snapshot) {
                        Restaurant res= snapshot.getValue(Restaurant.class);
                    }
                    @Override
                    public void onCancelled(DatabaseError firebaseError) {
                        System.out.println("The read failed: " + firebaseError.getMessage());
                    }
    
                    // ...
                });
            }
    
            @Override
            public void onKeyExited(String key) {
                System.out.println(String.format("Key %s is no longer in the search area", key));
            }
    
            @Override
            public void onKeyMoved(String key, GeoLocation location) {
                System.out.println(String.format("Key %s moved within the search area to [%f,%f]", key, location.latitude, location.longitude));
            }
    
            @Override
            public void onGeoQueryReady() {
                System.out.println("All initial data has been loaded and events have been fired!");
            }
    
            @Override
            public void onGeoQueryError(DatabaseError error) {
                System.err.println("There was an error with this query: " + error);
            }
        });
    

    但我仍然担心这是从数据库获取餐厅的最有效方式,因为我对“restaurants”根目录上的每个餐厅键单独运行查询。有没有人知道更有效的方法请告诉我们。

    【讨论】:

    • 是的,如果这是最有效的方法,得到答案会很有趣。弗兰克·范·普菲伦...谢谢 ^^
    猜你喜欢
    • 1970-01-01
    • 2018-10-30
    • 1970-01-01
    • 1970-01-01
    • 2015-12-05
    • 1970-01-01
    • 1970-01-01
    • 2012-10-26
    • 1970-01-01
    相关资源
    最近更新 更多