Как использовать временную метку сервера Firebase для создания даты?
В настоящее время версия Google ServerValue.TIMESTAMP
возвращает {".sv":"timestamp"}
, которая используется в качестве директивы для Firebase для заполнения этого поля меткой времени сервера после сохранения данных на сервере Firebase.
Однако, когда вы создаете свои данные на стороне клиента, у вас нет фактической метки времени для воспроизведения (т.е. использовать в качестве даты создания). У вас будет только доступ к отметке времени после первоначального сохранения и последующего поиска, что, я думаю, иногда слишком поздно и не очень изящно.
Перед Google:
Обновление: игнорировать этот раздел, поскольку он неправильный - я неправильно понял примеры. ServerValue.TIMESTAMP
всегда возвращал {".sv":"timestamp"}
.
Насколько я понимаю, в предустановленной Firebase появилась доступная на сервере отметка времени, которая позволила вам получить фактическую метку времени:
import com.firebase.client.ServerValue;
ServerValue.TIMESTAMP // eg. 1466094046
(ref 1, ref 2)
Вопросы:
- Является ли такое сохранение/извлечение единственным способом получить дату создания сервера в экземплярах моей модели?
- Если да, вы можете предложить метод реализации такого шаблона?
- Я правильно понимаю ServerValue.TIMESTAMP изменился с приобретением Google Firebase? Обновление: Нет, @FrankvanPuffelen ответил, что во время приобретения ничего не изменилось.
Примечание:
Я не рассматриваю возможность использования new Date()
на стороне клиента, поскольку я читал его небезопасно, хотя, пожалуйста, поделитесь своими мыслями, если вы считаете, что разные.
Ответы
Ответ 1
Когда вы используете константу ServerValue.TIMESTAMP
в операции записи, вы говорите, что сервер базы данных Firebase должен определить правильную метку времени, когда она выполняет операцию записи.
Скажем, мы запускаем этот код:
ref.addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
System.out.println(dataSnapshot.getValue());
}
public void onCancelled(DatabaseError databaseError) { }
});
ref.setValue(ServerValue.TIMESTAMP);
Это будет выполняться следующим образом:
- вы присоединяете слушателя
- вы пишете значение с помощью
ServerValue.TIMESTAMP
- Клиент Firebase немедленно запускает событие значения с приближением метки времени, которую он будет писать на сервере.
- ваш код печатает это значение
- операция записи отправляется серверам Firebase
- серверы Firebase определяют фактическую метку времени и записывают значение в базу данных (при условии, что правила безопасности не сработают)
- сервер Firebase отправляет фактическую метку времени клиенту
- Клиент Firebase вызывает событие значения для фактического значения
- ваш код печатает это значение
Если вы используете ChildEventListener
вместо ValueEventListener
, тогда клиент будет вызывать onChildAdded
на шаге 3 и onChildChanged
на шаге 8.
Ничего не изменилось в способе создания ServerValue.TIMESTAMP
, поскольку Firebase присоединилась к Google. Код, который работал до этого, будет продолжать работать. Это также означает, что первый ответ, который вы связали, является допустимым способом его обработки.
Ответ 2
Я делаю это по-другому.
Решение 1: push()
метод в POJO
Поскольку я не хочу загромождать свои POJO со странными getters или свойствами, я просто определяю метод push()
внутри своих POJO, который выглядит следующим образом:
/**
* Pushes a new instance to the DB.
*
* @param parentNode `DatabaseReference` to the parent node this object shall be attached to
*/
fun push(parentNode: DatabaseReference) {
parentNode
.push()
.apply {
setValue([email protected])
child(Pojo.CREATED_AT_KEY).setValue(ServerValue.TIMESTAMP)
}
}
Затем я могу просто создать экземпляр POJO и вызвать push()
на нем, который правильно заполняет свойство времени создания.
Это определенно делает POJO немного менее понятным и включает в себя логику, о которой POJO не должен знать. Однако использование @Exclude
аннотаций и/или кастингов, как описано в некоторых ответах здесь, также требует знания механизма хранения.
Решение 2: Помощник или расширение DatabaseReference
(Kotlin)
Чтобы преодолеть это, вы, конечно, можете просто создать метод pushTask(task: Task)
в помощнике или - если используете Kotlin - метод расширения, например. DatabaseReference
, который может выглядеть так:
fun DatabaseReference.push(pojo: Pojo) {
push()
.apply {
setValue(pojo)
child(Pojo.CREATED_AT_KEY).setValue(ServerValue.TIMESTAMP)
}
}
Глядя на это сейчас, я пришел к мысли, что мне действительно нравится второй подход (если у меня есть Котлин в моем распоряжении - мне не нравятся помощники). Но это, вероятно, только вопрос вкуса.;)