Хранение дополнительных данных под узлами GeoFire
Я храню данные о местоположении через GeoFire в моей базе данных, вот структура:
geofire
-Ke1uhoT3gpHR_VsehIv
-Kdrel2Z_xWI280XNfGg
-g: "dr5regw90s"
-l
-0: 40.7127837
-1: -74.00594130000002
Предполагается хранить информацию о местоположении и данные о географическом пожаре в отдельных узлах, однако я вижу преимущество в хранении некоторых дополнительных данных в этих узлах географического пожара, таких как название предприятия. Таким образом, мне нужно было всего лишь сделать один звонок в мою базу Firebase, чтобы получить информацию о ближайших местах и их названиях.
Это достижимо через key_entered
метод? Кто-нибудь создал подобное решение? Действительно ли это плохая идея, даже если информация о местоположении постоянно обновляется?
Любой вклад приветствуется!
3 ответа
Во-первых, структура, которую вы используете для приложения, неверна.
давайте рассмотрим пример приложения пользователя
Когда вы используете Geofire, у вас есть два списка данных:
a list of user details for each user
a list of latitude and longitude coordinates for each user
Вы пытаетесь хранить оба в одной структуре, как это
"users" : {
<userId> : {
"userData" : "userData",
<geofireData>
...
}
}
Пытаться хранить пользовательские данные и геофилиданные в одном узле - плохая идея, поскольку вы смешиваете в основном статические данные (свойства вашего пользователя) с очень изменчивыми данными (информация о географическом местоположении). Разделение этих двух данных приводит к повышению производительности, вот почему Geofire обеспечивает его соблюдение.
Вот почему, когда вы пытаетесь добавить данные геолокации в пользовательский узел, он перезаписывает данные предыдущего пользователя для этого узла.
Ваша структура базы данных должна быть такой.
"Users" : {
<UserId> : {
"UserData" : "UserData",
...
}
}
"Users_location" : {
<UserId> : {
<geofireData> ...
}
}
Следовательно, для одного и того же идентификатора пользователя вы создаете 2 структуры: одну для сведений о пользователе, а другую для сведений о геолокации этого пользователя.
Как подтолкнуть пользователя и установить данные географического огня.
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));
user Id, который вы используете в геолокации, тот же, что и во время push().
Следовательно, для каждого user Id у вас есть userdetails в одной структуре и детали местоположения в другой структуре.
Чтобы получить данные, сначала нужно выполнить GeoQuery на узле users_location, а затем получить данные с помощью метода onKeyEntered. Ключ параметра - это user Id из моего примера.
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 без удаления существующих данных с помощьюgeoFire.setLocation("id", location);
как сообщается в этом выпуске https://github.com/firebase/geofire-java/issues/134.
Это мое решение.
1. Настройка смешанных данных с помощью GeoFire на FireBase
Рассмотрим ниже структуру:
|-userExtra :
|-userId1 :
|- userId : "userId1",
|- userName : "Name1",
|- <geofireData> (i and g)
|...
|-userId2 :
|- userId : "userId2",
|- userName : "Name2",
|- <geofireData> (i and g)
|...
Вы можете сгенерировать geoHash с помощью GeoHash geoHash = new GeoHash(location)
и установите значение для дочернего элемента прямо в базе огня.
/*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? Кто-нибудь создавал подобное решение? Неужели это действительно так плохо, даже если информация о местоположении постоянно обновляется?
Я бы сказал, что вы не можете получить и дополнительные данные, и GeoFire, используя только GeoQueryEventListener
с onKeyEntered
. Вам нужно будет использовать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.
I had this solution I am using now for Javascript:
- Save any extra info with key separated by symbol i.e. underscore
- Make sure auth id is in the key, which is used in security rules to ensure only the user can write to their node
"geofire": {"$keywithextrainfo":{".read":"true",".write":"$keywithextrainfo.contains(auth.uid)"}
- Client-side, separate the information by the underscore