【问题标题】:Storing Extra Data Under GeoFire Nodes在 GeoFire 节点下存储额外数据
【发布时间】:2017-03-05 12:20:17
【问题描述】:

我通过 GeoFire 在我的数据库中存储位置数据,结构如下:

geofire
  -Ke1uhoT3gpHR_VsehIv
  -Kdrel2Z_xWI280XNfGg
    -g: "dr5regw90s"
    -l
      -0: 40.7127837
      -1: -74.00594130000002

建议将位置信息和 geofire 数据存储在单独的节点中,但是我认为在这些 geofire 节点下存储 一些 额外数据的优势,例如一个企业的名称。这样,我只需调用 Firebase 一次即可获取附近的位置及其名称。

这可以通过key_entered 方法实现吗?有没有人创建过类似的解决方案?即使位置信息不断更新,这真的有那么糟糕吗?

感谢任何输入!

【问题讨论】:

  • 我不会反对创建 Geofire 和它所基于的 Firebase 数据库的人们提出的建议。当用于多个键时,额外的调用不会产生太多开销。见stackoverflow.com/questions/35931526/…

标签: firebase geofire


【解决方案1】:

首先,您用于应用程序的结构是错误的。

让我们以用户应用为例

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

a list of user details for each user
a list of latitude and longitude coordinates for each user

您正试图将两者存储在这样的相同结构中

"users" : {
    <userId> : {
        "userData" : "userData",
         <geofireData> 
        ...
    }
}

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

这就是为什么当您尝试将地理位置数据添加到用户节点时,它会覆盖该节点之前的用户详细信息。

你的数据库结构应该是这样的。

"Users" : {
    <UserId> : {
        "UserData" : "UserData",
        ...
    }
}
"Users_location" : {
    <UserId> : {
        <geofireData> ...
    }
}

因此,对于同一个用户 ID,您创建了 2 个结构,一个用于用户详细信息,另一个用于该用户的地理位置详细信息。

如何推送用户并设置geofire数据。

String userId = ref.child("users").push().getKey();

ref.child("users").child(userId).setValue(user);

geoFire = new GeoFire(ref.child("user_location"));
geoFire.setLocation(userId, new GeoLocation(lattitude, longitude));

您在地理定位中使用的 userId 与您在 push() 中获得的相同。

因此,对于每个 userId,您在一个结构中都有用户详细信息,在另一个结构中具有位置详细信息。

要获取数据,首先需要在 users_location 节点执行 GeoQuery,然后通过 onKeyEntered 方法获取数据。参数键是我示例中的 userId。

geoFire=newGeoFire(FirebaseDatabase.getInstance().getReference().child("users_location");
geoQuery = geoFire.queryAtLocation(geoLocation), radius);
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
    @Override
    public void onKeyEntered(String key, GeoLocation location) {
         //retrieve data
//use this key which is userId to fetch user details from user details structure
    }
};    

编码愉快:)

【讨论】:

    【解决方案2】:

    可能会迟到,但以防其他人面临同样的问题。

    很有可能将 GeoFire 数据与现有数据进行集成和操作。 许多开发人员面临的主要挑战是他们无法在不删除现有数据的情况下更新 GeoFire 地理定位,如本期 geofire-java/issues/134 中所述,使用 geoFire.setLocation("id", location); 删除现有数据。

    这是我的解决方案。

    1.在 FireBase 上使用 GeoFire 设置混合数据

    让我们考虑下面的结构:

    |-userExtra : 
        |-userId1 : 
           |- userId : "userId1",
           |- userName : "Name1",
           |- <geofireData> (i and g)
           |...
    
        |-userId2 : 
           |- userId : "userId2",
           |- userName : "Name2",
           |- <geofireData> (i and g)
           |...
    

    您可以使用GeoHash geoHash = new GeoHash(location) 生成geoHash,并直接在firebase 中将值设置为子级。

    /*Java Code*/
    void setGeoFireMixData(UserExtra user, Location location){
       DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
       ref = ref.child("users").child(user.userId);
    
       //Setting userData if needed
       ref.child("userId").setValue(user.id);
       ref.child("Name").setValue(user.name);
       // .... other references
    
       //Setting GeoFire Data
       GeoHash geoHash = new GeoHash(location);
       ref.child("l").setValue(Arrays.asList(location.latitude, location.longitude));
       ref.child("g").setValue(geoHash.getGeoHashString());
    }
    

    2。使用 GeoFire 获取混合数据

    关于问题: 这可以通过 key_entered 方法实现吗?有没有人创建过类似的解决方案?即使位置信息不断更新,这真的有那么糟糕吗?

    我想说,您不能仅使用 GeoQueryEventListeneronKeyEntered 来检索额外数据和 GeoFire。您将需要使用GeoQueryDataEventListener。为此,您可以考虑上面定义的结构来定义数据的 PoJo。

    ...
    GeoQueryDataEventListener geoQueryDataEventListener = new GeoQueryDataEventListener() {
      @Override
      public void onDataEntered(DataSnapshot dataSnapshot, GeoLocation location) {
          UserExtra user = dataSnapshot.getValue(UserExtra.class);
          actionOnUser(user);
      }
      ...
    };
    ...
    geoQuery = geoFire.queryAtLocation(new GeoLocation(latitude,longitude), 0.5);
    geoQuery.addGeoQueryDataEventListener(geoQueryDataEventListener);
    ...
    

    UserExtra 类可以定义如下:

    public class UserExtra implements Serializable {
       String userId;
       String name;
        ...
       List<Double> l; //GeoLocation
       String g;
    }
    

    这将为您提供节点中的所有数据,包括 geoFire 数据。

    【讨论】:

    • 这是一个更好的解决方案。!!将 geofire 详细信息和 POJO 详细信息分开将增加数据库调用的数量。这很简单。
    【解决方案3】:

    我有这个解决方案,我现在正在使用 Javascript:

    1. 用符号分隔的键保存任何额外信息,即下划线

    2. 确保 auth id 在密钥中,用于安全规则以确保只有用户可以写入其节点

      “规则”:{ “地火”:{ ".read":"真", "$extrainformation_authid":{ ".write":"$extrainformation_authid.contains(auth.uid)" } } }

    3. 客户端,用下划线分隔信息

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-04
      • 1970-01-01
      • 1970-01-01
      • 2014-03-08
      • 2011-07-28
      相关资源
      最近更新 更多