Хранение дополнительных данных под узлами 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:

  1. Save any extra info with key separated by symbol i.e. underscore
  2. 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)"}

  1. Client-side, separate the information by the underscore
Другие вопросы по тегам