19

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

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

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 坐标,而不是 node 下的其他项目requests

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

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

4

4 回答 4

39

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

{
"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
    }
};    

希望这可以帮助。

编辑 如何推送项目并设置 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);
于 2016-07-13T06:53:00.277 回答
13

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

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

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

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

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

于 2016-07-13T01:09:22.267 回答
1

对于那些最近带着同样的问题来这篇文章的人,这可以通过Geofirestore库来实现,它支持基于 Firebase Firestore 数据库构建的应用程序的 Geofire。

于 2018-07-10T21:01:56.433 回答
1

您可以使用 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);
       });
    }
}
于 2017-05-15T17:51:11.580 回答