Android 如何将GeoFire坐标与Firebase数据库中的其他项目一起保存?

Android 如何将GeoFire坐标与Firebase数据库中的其他项目一起保存?,android,firebase,firebase-realtime-database,geofire,Android,Firebase,Firebase Realtime Database,Geofire,我正在开发一个应用程序,并在Firebase数据库中保存一些字符串,如postedAtTime,postedBy,postedOnDate。我想将GeoFire坐标保存在保存上述所有字符串的同一个节点中,以便以后可以轻松地进行查询 以下是我保存所有字符串的路径: databaseReferenceHRequests = firebaseDatabase.getReferenceFromUrl("https://appName-e1a35.firebaseio.com/requests/");

我正在开发一个应用程序,并在Firebase数据库中保存一些字符串,如
postedAtTime
postedBy
postedOnDate
。我想将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坐标,而没有保存节点
请求下的其他项目

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


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

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

  • 具有常规属性的项的列表
  • 通过Geofire查询的geohash索引及其关联键的列表
  • 您可以使用这些键从Geoquery结果获取常规项。这就是为什么Geofire的事件被称为“输入键”、“退出键”等

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


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

    Frank的回答是正确的,但我想给出一个示例。 您的数据库结构应该是这样的

    {
    "items" : {
        <itemId> : {
            "someData" : "someData",
            ...
        }
      },
    "items_location" : {
        <itemId> : {
            <geofireData> ...
        }
      }
    }
    
    希望这有帮助

    编辑 如何推送项目并设置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调用中保存项目数据和geofire数据

    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);
    
    GeoHash GeoHash=new GeoHash(新地理位置(纬度、经度));
    映射更新=新的HashMap();
    updates.put(“items/”+itemId,item);
    updates.put(“items_location/”+itemId+“/g”,geoHash.getgeohashring());
    updates.put(“items_location/”+itemId+“/l”,Arrays.asList(纬度、经度));
    参考updateChildren(更新);
    
    您可以使用Firebase功能在每个新条目上为您输入它


    对于那些最近带着相同问题来到本帖的人,这是可能的,因为该库支持Geofire,用于构建在Firebase Firestore数据库之上的应用程序。

    感谢您的回答,但我不确定我是否得到了问题的答案。我的意思是,我怎样才能从数据库中检索到用户半径在0.5公里以内的帖子?我还保存了帖子发布位置的纬度和经度。请澄清一点,先生。Geofire是否只返回节点中的密钥,然后您必须查询常规属性节点。或者Geofire也会返回常规属性数据吗?@Frank你能解释一下如何存储geohash索引以及它的结构是什么吗。问题是我的
    是一个推送id。我如何跟踪它?请让我知道。是否需要先获取
    itemId
    ,然后推送数据。。。我不能先推送数据,然后再获取
    itemId
    (pushId)吗?看起来没有其他有效的方法了。如果通过调用
    ref.push().setValue(item)
    首先推送数据,则无法获取推送id,因此无法执行
    geoFire.setLocation()
    。很抱歉,提出一篇旧帖子,但我如何处理这两个操作的原子性?我的意思是,我可以使用updateChildren,但geofire在内部处理插入。后续问题“geofire是否在项和项位置之间强制使用相同的键?”
    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);
    
    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);
           });
        }
    }