【问题标题】:How to save GeoFire coordinates along with other items in Firebase database?如何将 GeoFire 坐标与 Firebase 数据库中的其他项目一起保存?
【发布时间】:2016-11-15 09:47:28
【问题描述】:

我正在开发一个应用程序并在 Firebase 数据库中保存一些字符串,例如 postedAtTimepostedBypostedOnDate。我想将 GeoFire 坐标保存在保存上述所有字符串的同一节点中,以便稍后我可以轻松地进行查询。

这是我保存所有字符串的路径:

databaseReferenceHRequests = firebaseDatabase.getReferenceFromUrl("https://appName-e1a35.firebaseio.com/requests/");

这就是我保存它的方式:

// in onButtonClicked method:
postNewRequest(null, imageUID, MainActivity.userName.getText().toString(), time, date, utcFormatDateTime, MainActivity.userEmail.getText().toString(), geoFire);

// the method:
public void postNewRequest(Bitmap bitmap, String imageUIDh, String postedBy, String postedAtTime, String postedOnDate, String utcFormatDateTime, String userEmail, GeoFire geoFire) {
    HRequest hRequest = new HelpRequest(null, imageUIDh, postedBy, postedAtTime, postedOnDate, utcFormatDateTime, userEmail, geoFire);
    databaseReferenceHRequests.push().setValue(hRequest);
}

以下是它在数据库中的保存方式:

我想要的是将 GeoFire 坐标保存在同一个节点中,这里是-KLIoLUsI0SpQZGpV1h4。这只是一个推送 ID,它是随机生成的。

我通过提供此参考进行了尝试:

geoFire = new GeoFire(firebaseDatabase.getReferenceFromUrl("https://appName-e1a35.firebaseio.com/requests/"));

然后将其与其他项目一起推送,如上图所示。但是,这仅保存了 GeoFire 坐标,而不是节点 requests 下的其他项目。

那么,我的 GeoFire 参考应该是什么,以便它与同一节点中的所有数据一起保存?

这里出了什么问题?请告诉我。

【问题讨论】:

    标签: android firebase firebase-realtime-database geofire


    【解决方案1】:

    弗兰克的回答是正确的,但我想举个例子。 你的数据库结构应该是这样的。

    {
    "items" : {
        <itemId> : {
            "someData" : "someData",
            ...
        }
      },
    "items_location" : {
        <itemId> : {
            <geofireData> ...
        }
      }
    }
    

    要获取数据,首先需要在items_location 节点上进行GeoQuery,然后通过onKeyEntered 方法获取数据。在我的示例中,参数keyitemId

    geoFire = new GeoFire(FirebaseDatabase.getInstance().getReference().child("items_location");
    geoQuery = geoFire.queryAtLocation(geoLocation), radius);
    geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
        @Override
        public void onKeyEntered(String key, GeoLocation location) {
             //retrieve data
        }
    };    
    

    希望这会有所帮助。

    编辑 如何推送item并设置geofire数据。

    String itemId = ref.child("items").push().getKey();
    
    ref.child("items").child(itemId).setValue(item);
    
    geoFire = new GeoFire(ref.child("items_location"));
    geoFire.setLocation(itemId, new GeoLocation(lattitude, longitude));
    

    编辑在一次 API 调用中保存项目数据和地理火灾数据

    GeoHash geoHash = new GeoHash(new GeoLocation(latitude, longitude));
    Map<String, Object> updates = new HashMap<>();
    updates.put("items/" + itemId, item);
    updates.put("items_location/" + itemId + "/g", geoHash.getGeoHashString());
    updates.put("items_location/" + itemId + "/l", Arrays.asList(latitude, longitude));
    ref.updateChildren(updates);
    

    【讨论】:

    • 感谢您的回答。问题是我的&lt;itemId&gt; 是一个推送ID。我怎样才能跟踪它?请告诉我。
    • 是不是需要先获取itemId再推送数据...不能先推送数据再获取itemId(pushId)吗?
    • 看起来没有比这更有效的方法了。如果先调用ref.push().setValue(item)推送数据,则无法获取推送id,因此无法进行geoFire.setLocation()
    • 很抱歉提出一个旧帖子,但我该如何处理两个操作的原子性?我的意思是,我可以使用 updateChildren,但 geofire 在内部处理插入。
    • 后续问题“GeoFire 是否在 item 和 item_location 之间强制使用相同的键?”:stackoverflow.com/q/49379357/2327328
    【解决方案2】:

    当您使用 Geofire 时,您有两个数据列表:

    1. 具有常规属性的项目列表
    2. geohash 索引及其关联键的列表,您可以通过 Geofire 查询这些索引

    您使用键从地理查询结果中获取常规项目。这就是为什么 Geofire 的事件被称为“Key Entered”、“Key Exited”等的原因。

    尝试将它们存储在一个节点中是一个坏主意,因为您将大部分静态数据(项目的属性)与高度易变的数据(地理位置信息)混合在一起。将两者分开会带来更好的性能,这就是 Geofire 强制执行它的原因。

    虽然可能存在属性和地理数据同​​样动态/静态的用例,但 GeoFire 不支持将地理数据和其他属性保存在一个位置。

    【讨论】:

    • 感谢您的回答,但我不确定我是否得到了问题的答案。我的意思是我如何才能从用户半径 0.5 公里范围内的数据库中检索那些帖子?我还保存了发布帖子的纬度和经度。先生,请说得更清楚。
    • Geofire 是否只返回节点中的键,然后您必须查询常规属性节点。还是 Geofire 也返回常规属性数据?
    • @Frank 你能解释一下如何存储 geohash 索引以及它的结构
    【解决方案3】:

    您可以使用 Firebase 函数在每个新条目中为您输入它

    let functions = require('firebase-functions');
    
    let GeoFire = require('geofire');
    
    exports.testLocation = functions.database.ref('/items/{item}').onWrite(event => {
    let data = event.data.val();
       console.log(data);
       console.log(event.params.item);
    
       if (data.location && data.location.coords) {
    
           console.log('Update GeoFire');
    
           let ref = event.data.adminRef.parent.parent.child('/items_locations'));
    
           let key = event.params.test;
           let location = [data.location.coords.latitude, data.location.coords.longitude]);
           let geoFire = new GeoFire(ref);
    
           geoFire.set(key, location).then(() => {
              console.log('Update succesfull');
           }).catch(error => {
              console.log(error);
           });
        }
    }
    

    【讨论】:

      【解决方案4】:

      对于那些最近来到这篇文章的人来说,这是可能的,Geofirestore 库支持基于 Firebase Firestore 数据库构建的应用程序的 Geofire。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-04-09
        • 2011-04-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多