在 GeoFire 节点下存储额外数据

Storing Extra Data Under GeoFire Nodes

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

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

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

这可以通过 key_entered 方法实现吗?有没有人创建过类似的解决方案?即使位置信息不断更新,这真的是个坏主意吗?

欢迎任何意见!

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

让我们以用户应用为例

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

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

您正在尝试将两者存储在相同的结构中,如下所示

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

尝试将用户数据和 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() 中获得的相同。

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

要获取数据,首先需要在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
    }
};    

编码愉快:)

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

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

这是我的解决方案。

1.在 FireBase

上使用 GeoFire 设置混合数据

Let's consider below Structure:

|-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

获取混合数据

About the question: Is this achievable via the key_entered method? Has anyone created a similar solution? Is this truly that bad of an idea even if the location info is consistently updated?

我会说,你不能仅使用 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);
...

class UserExtra 可以定义如下:

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

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

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

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

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

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

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