web-dev-qa-db-fra.com

Comment utiliser l'horodatage du serveur Firebase pour générer la date de création?

Actuellement, la version Google de ServerValue.TIMESTAMP Renvoie {".sv":"timestamp"} Qui est utilisé comme directive pour Firebase pour remplir ce champ avec l'horodatage du serveur une fois que vous avez enregistré les données sur le serveur Firebase.

Cependant, lorsque vous créez vos données côté client, vous ne disposez pas encore de l'horodatage réel (c'est-à-dire, utilisez-le comme date de création). Vous n'aurez accès à l'horodatage qu'après la sauvegarde initiale et la récupération qui en résulte, ce qui - j'imagine - est parfois trop tard et pas très élégant.


Avant Google:

Mise à jour: Ignorez cette section car elle est incorrecte - J'ai mal compris les exemples. ServerValue.TIMESTAMP Renvoyait toujours le {".sv":"timestamp"}.

Autant que je sache dans Firebase pré-google, il semblait y avoir un horodatage généré par le serveur disponible qui vous permettait d'acquérir l'horodatage réel:

import com.firebase.client.ServerValue;
ServerValue.TIMESTAMP // eg. 1466094046

( réf 1 , réf 2 )


Questions:

  1. Une telle sauvegarde/récupération est-elle le seul moyen d'obtenir la date de création générée par le serveur sur mes instances de modèle?
  2. Si oui, pouvez-vous proposer une méthode de mise en œuvre d'un tel modèle?
  3. Est-ce que je comprends bien ServerValue.TIMESTAMP a changé avec l'acquisition de Firebase par Google? Mise à jour: Non, @FrankvanPuffelen a répondu que rien n'a changé pendant l'acquisition.

Remarque:

Je n'envisage pas d'utiliser new Date() côté client car j'ai lu que ce n'est pas sûr, mais veuillez partager vos pensées si vous pensez différemment.

15
Voy

Lorsque vous utilisez le ServerValue.TIMESTAMP constante dans une opération d'écriture, vous dites que le serveur de base de données Firebase doit déterminer l'horodatage correct lorsqu'il exécute l'opération d'écriture.

Disons que nous exécutons ce code:

ref.addValueEventListener(new ValueEventListener() {
    public void onDataChange(DataSnapshot dataSnapshot) {
        System.out.println(dataSnapshot.getValue()); 
    }

    public void onCancelled(DatabaseError databaseError) { }
});
ref.setValue(ServerValue.TIMESTAMP);

Cela s'exécutera comme suit:

  1. vous attachez un auditeur
  2. vous écrivez une valeur avec ServerValue.TIMESTAMP
  3. le client Firebase déclenche immédiatement un événement de valeur avec une approximation de l'horodatage qu'il écrira sur le serveur
  4. votre code imprime cette valeur
  5. l'opération d'écriture est envoyée aux serveurs Firebase
  6. les serveurs Firebase déterminent l'horodatage réel et écrivent la valeur dans la base de données (en supposant qu'aucune règle de sécurité n'échoue)
  7. le serveur Firebase renvoie l’horodatage réel au client
  8. le client Firebase déclenche un événement de valeur pour la valeur réelle
  9. votre code imprime cette valeur

Si vous utilisez ChildEventListener au lieu d'un ValueEventListener, le client appellera onChildAdded à l'étape 3 et onChildChanged à l'étape 8.

Rien n'a changé dans la façon dont nous générons le ServerValue.TIMESTAMP depuis que Firebase a rejoint Google. Le code qui fonctionnait auparavant continuera de fonctionner. Cela signifie également que le première réponse que vous avez liée est un moyen valide de le gérer.

26
Frank van Puffelen

Je le fais un peu différemment.

Solution 1: Push() méthode dans POJO

Comme je ne veux pas encombrer mes POJO avec des getters ou des propriétés étranges, je définis juste une méthode Push() à l'intérieur de mes POJO qui ressemble à ceci:

/**
 * 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(this@Pojo)
            child(Pojo.CREATED_AT_KEY).setValue(ServerValue.TIMESTAMP)
        }
}

Ensuite, je peux simplement créer une instance de POJO et appeler Push() dessus qui remplit correctement la propriété time de création.

Cela rend le POJO un peu moins clair et implique une logique qu'un POJO ne devrait pas connaître. Cependant, l'utilisation d'annotations et/ou de transtypages @Exclude Comme indiqué dans certaines réponses ici nécessite également la connaissance du mécanisme de stockage.

Solution 2: Aide ou extension DatabaseReference (Kotlin)

Pour surmonter cela, vous pouvez bien sûr également créer une méthode pushTask(task: Task) dans une aide ou - si vous utilisez Kotlin - une méthode d'extension pour par exemple DatabaseReference qui pourrait ressembler à ceci:

fun DatabaseReference.Push(pojo: Pojo) {
    Push()
    .apply {
        setValue(pojo)
        child(Pojo.CREATED_AT_KEY).setValue(ServerValue.TIMESTAMP)
    }
}

En y regardant maintenant, j'en viens à penser que j'aime plus la deuxième approche ( si J'ai Kotlin à ma disposition - je n'aime pas les assistants). Mais ce n'est probablement qu'une question de goût. ;)

2
ubuntudroid