iqpolar
iqpolar

Reputation: 145

How to use end datetime in Firebase Realtime Database

In our app it is really important to also save the end datetime of a new data.

For example, if writing a new message, I would like it to be visible for users only ten hours. With rest api & sql database, I can easily create end datetime with server time(+ten hours) and save the message in database. When loading messages for users, I can select all messages where end datetime is before now.

How can I do this with Firebase Realtime Database? Maybe with Firebase Cloud Functions? I don't want to use client time.

Upvotes: 2

Views: 4120

Answers (1)

Grimthorr
Grimthorr

Reputation: 6926

This would actually be a good usage example for Cloud Functions.

When saving the message to the database, you can use ServerValue.TIMESTAMP to automatically insert the Firebase server's timestamp, so you could do something like:

public void saveMessage(String content) {
    DatabaseReference messagesRef = FirebaseDatabase.getInstance().getReference("messages");

    HashMap<String, Object> message = new HashMap<>();
    message.put("content", content);
    message.put("startTime", ServerValue.TIMESTAMP);

    messagesRef.push().setValue(message);
}

Then you could attach a Cloud Function to the messages location to listen for new data. This function could perform the logic of adding 10 hours to the startTime value and saving it as endTime back to the same child, something like:

exports.calculateEndTime = functions.database
    .ref('/messages/{messageId}').onCreate(event => {
      const message = event.data.val();

      // Only calculate endTime if it doesn't already exist.
      if (message && !message.endTime) {
        // Add 10 hours (in milliseconds) to the startTime to obtain the endTime.
        const endTime = message.startTime + (10 * 3600000);

        // Update the Firebase Database with the new endTime value.
        return event.data.adminRef.update({
          endTime: endTime
        });
      }
    });

Finally, to query the list of messages to only obtain those where the endTime has not yet passed, you could do something like:

// Obtain the server time using the .info/serverTimeOffset value.
DatabaseReference offsetRef = FirebaseDatabase.getInstance().getReference(".info/serverTimeOffset");
offsetRef.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot snapshot) {
        // Calculate the estimated server time based on the offset.
        double offset = snapshot.getValue(Double.class);
        double estimatedServerTimeMs = System.currentTimeMillis() + offset;

        // Use this server time to get the messages.
        getMessages(estimatedServerTimeMs);
    }

    @Override
    public void onCancelled(DatabaseError error) { }
});

public void getMessages(double endTime) {
    DatabaseReference messagesRef = FirebaseDatabase.getInstance().getReference("messages");

    // Create a query to limit results where endTime is greater than the current time.
    Query messagesQuery = messagesRef.orderByChild("endTime").startAt(endTime);

    messagesRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            for (DataSnapshot message : dataSnapshot.getChildren()) {
                // ...
            }
        }

        @Override
        public void onCancelled(FirebaseError firebaseError) { }
    });
}

This example first grabs the clock skew value (from .info/serverTimeOffset) to calculate the estimated current server time and then uses this in a startAt() query to only return messages with an endTime after the current time.


There's likely a few other ways to approach this too, like obtaining the server timestamp and performing the logic above while saving the message, or even just querying on the startTime (using startAt 10 hours ago).

However, using the Cloud Functions route is a good way to ensure that the endTime is calculated server-side, saving of a new message is performed quickly and the messages actually contain an endTime value in the database.

Upvotes: 5

Related Questions