在 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?
我会说,你不能仅使用 GeoQueryEventListener
和 onKeyEntered
来检索额外数据和 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:
保存任何额外的信息,键用符号分隔,即下划线
确保 auth id 在密钥中,它用于安全规则以确保只有用户可以写入他们的节点
“规则”:{
“geofire”:{
“.read”:“真”,
“$extrainformation_authid”:{
".write":"$extrainformation_authid.contains(auth.uid)"
}
}
}
客户端,信息之间用下划线分隔
我在我的数据库中通过 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?
我会说,你不能仅使用 GeoQueryEventListener
和 onKeyEntered
来检索额外数据和 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:
保存任何额外的信息,键用符号分隔,即下划线
确保 auth id 在密钥中,它用于安全规则以确保只有用户可以写入他们的节点
“规则”:{ “geofire”:{ “.read”:“真”, “$extrainformation_authid”:{ ".write":"$extrainformation_authid.contains(auth.uid)" } } }
客户端,信息之间用下划线分隔