skip to Main Content

I have a Kotlin data class that effortlessly adds a Firestore server upload timestamp to an object when it’s saved as a document to the Firestore database in the cloud.

All I have to do is add a FieldValue property to the Kotlin data class in the Android client, complete with the default value FieldValue.serverTimestamp(), and the object serializes to a Firestore document with the correct upload timestamp without any more effort from me:

data class CloudEntity(
  val uu: String = "",
  val de: String = "",
  ...
  val cr: Long = 0L,
  val ts: FieldValue = FieldValue.serverTimestamp() //server timestamp
)

But when I try to deserialize that Firestore document back to that exact same data class, using something like documentChange.document.toObject<CloudEntity>(), I get the error No properties to serialize found on class com.google.firebase.firestore.FieldValue.

So how do I deserialize that timestamp property?

I don’t actually need that timestamp value on the client (it’s only used in server-side queries), so I’d also be happy to implement a solution that doesn’t actually deserialize the server timestamp value but simply discards the value and returns a zero value or something. Just as long as it doesn’t crash the whole deserialization.

2

Answers


  1. I suggest you to create a separate object to retrieve from cloud but without that field! Something like this:

    data class CloudEntity(
        val uu: String = "",
        val de: String = "",
        val cr: Long = 0L,
        val ts: FieldValue = FieldValue.serverTimestamp() //server timestamp
    )
    
    // Domain entity
    data class Entity(
        val uu: String = "",
        val de: String = "",
        val cr: Long = 0L
    )
    
    // Mapper from domain to cloud
    fun Entity.toCloud() = CloudEntity(uu, de, cr)
    

    FieldValue.serverTimestamp() just returns a sentinel object that you use when writing a field to a document. It indicates the server should replace it with an actual Timestamp object. serverTimestamp() itself does not contain any date information, and you can’t convert it to a date.

    When you write the sentinel value to a document, and read it back out, it will become a Timestamp type object, which you can convert to a native Date object with its toDate() method, if you want to. You could add a ‘val ts: Date’ into the Entity class I wrote before, and then retrieve that value.

    If you don’t want to create that separate Entity without that field, you could remove that field from your CloudEntity class and add that field as an update to the document in your ‘write’ method.

    Login or Signup to reply.
  2. While Matilveiro’s solution might work, please note that isn’t quite necessary. If you want to have a Timestamp type field inside your CloudEntity class, the simplest solution in Kotlin would be to define the ts field to be of type Date and use an annotation like this:

    @ServerTimestamp
    var ts: Date? = null
    

    There is no need to initialize the field in any way. So when you create an object of the CloudEntity class you don’t have to pass anything to the constructor. Firebase servers will read your ts field, as it is a ServerTimestamp (see the annotation), and it will populate that field accordingly.

    On the other hand, if you have used a Map, then indeed you had to pass FieldValue.serverTimestamp() as value:

    val cloudEntry = mapOf(
        "ts" to FieldValue.serverTimestamp(),
        //Other fields.
    )
    

    So it’s one or the other.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search