How to use end datetime in Firebase Realtime Database - android

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.

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.

Related

Retrieve data from multiple push ids under a single child in firebase realtime database

I am new to android studio and programming and am currently trying to make my first app. In firebase RTDB, I have multiple push ids under a single child that keep on increasing in number as the user presses certain buttons, and they all store only an integer. I want to retrieve the data from all those push ids(or keys, I don't really know what they are actually called) under the child and then sum the integers up and display the result in a textView and do it every time a new field is added. How can I do that? So far I only know how to normally send and receive data to childs sub-childs like this but i have never ever used push ids or keys before:
String recieve = datasnapshot.child("Child").child("subchild").getText().toString();
String send = "send";
databaseReferenc.child("Child").child("sunchile").setValue(send);
The data tree in firebase is as follows:
Assuming that Australia is a direct child of your Firebase Realtime Database root, to sum all those values, please use the following lines of code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference australiaRef = rootRef.child("Australia");
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int total = 0;
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String value = Integer.parseInt(ds.getValue(String.class));
total += value;
}
Log.d("TAG", "total: " + total);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d("TAG", databaseError.getMessage()); //Don't ignore potential errors!
}
};
australiaRef.addListenerForSingleValueEvent(valueEventListener);
One more thing. Because you are storing numbers, it best to store them as long values and not as String values.

Get current server Date and Time in Firebase Firestore

I want to get my server time in Firebase Firestore so I can use it for my countdown logic. I can't find anywhere and mostly they suggest to use FiedValue.serverTimeStamp or ServerValue.TIMESTAMP which is both are used to save data. I don't want to save data I just want to get the server time.
Is there a static way like FirebaseFirestore.getInstance().getServerTime()?
There is no provided method to get the actual server time.
Server timestamps are just token values on the client that are give a final value when they reach Firestore. The best you can do is write a server timestamp to a field in a document, then read the doucument back from Firestore after field has a value. Bear in mind that the timestamp will be "late" at that point, because of the time it takes your code to actually write and read the data. You have no guarantee how long that process will take.
For a more details explanation of how server timestamps work, read this article.
As per said by the #Doug there is no way of getting just only time from Firebase. However there are many round-ways for the same.
Firstly, you can use the count-down using the device of the app user since all the time in today era is synced with satellite. This can be done using:
Date dateStart = new Date();
Date dateEnd = new Date();
System.out.println(dateEnd.getTime() - dateStart.getTime()/1000);
Secondly, create an object in firebase for the starting time (for particular user) and then when the countdown is over then count the difference between the current time and the time uploaded in database.
FirebaseFirestore db = FirebaseFirestore.getInstance();
// At the time of setting.
Map<String, Object> map= new HashMap<>();
map.put("startTime", (new Date()).getTime());
db.collection(userdata).document(userid).set(map);
// At the time of retrieving:
db.collection(userdata).document(userid).get()
.addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
// Here you can get the time..
}
} else {
Log.d(TAG, "get failed with ", task.getException());
}
}
});
Now if you don't like any of the above method then you can file a support request for time at https://firebase.google.com/support

how to delete a node in firebase 8 hours after its creation [duplicate]

I want do delete some old data from my Firebase, and I have a hard time do make it work.
I tried this solution found here: Firebase chat - removing old messages
but this isn't deprecated.
so I try it this way:
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_MONTH, -30);
Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
String key = dataSnapshot.getKey();
Marker retrievemarker =dataSnapshot.getValue(Marker.class);
Calendar t3 = new
GregorianCalendar
(c.get(Calendar.YEAR),
c.get(Calendar.MONTH),
retrievemarker.getSavedate());
int date1= calendar.get(Calendar.DATE);
int date2= t3.get(Calendar.DATE);
Log.d("date1",""+date1);
Log.d("date2",""+date2);
if( date1 == date2 ){
myRef.child(key).setValue(null);
}
for explanation:
In my Firebase I save a object named Marker, this object got a variable to store the savedate, the date where the object was saved in the Firebase.
int date = c.get(Calendar.DATE);
marker.setSavedate(date);
I want to delete the object in the Firebase after 30 days. So I try to subtract 30 days from the Date Today than i want to compare this with the savedate from the Object if it equals i will delete the object from the Firebase.
For the Subtraction I refer to an answer from the following question: How to subtract X days from a date using Java calendar?
But it doesn´t work. If I add a Object today to the Firebase the two dates are always equal.
So I guess the subtraction doesn´t work.
What am I doing wrong?
Say that you have a data structure with nodes line this:
-KItqNxLqzQoLnUCb9sJaddclose
time: "Thu Apr 28 17:12:05 PDT 2016"
timestamp: 1461888725444
Each such node has a timestamp property that indicates when it was created. Preferably you'd set this property using Server Timestamp.
With this data structure, you can easily build a query that returns only the items older than 30 days and removes them:
long cutoff = new Date().getTime() - TimeUnit.MILLISECONDS.convert(30, TimeUnit.DAYS);
Query oldItems = ttlRef.orderByChild("timestamp").endAt(cutoff);
oldItems.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
for (DataSnapshot itemSnapshot: snapshot.getChildren()) {
itemSnapshot.getRef().removeValue();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
My Firebase structure is like -> firebaseurl.com/test/user_id/2017-05-12 and then my data is structured with time
So I am using
long cutoff = new Date().getTime()-TimeUnit.MILLISECONDS.convert(10, TimeUnit.DAYS);
//Get days number for delete data
Date d = new Date(cutoff );
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd");
String old_date = `dateFormatGmt.format(new Date(cutoff));
// Get date of deleting content
ref2 = new Firebase("firebaseurl.com/test/user_id/" + user_id); // Firebase url
ref2.child(old_date).removeValue(); //Remove element
It works for me
Another option is use PubSub google cloud with Schedule Functions from firebase, i'm using and i read documents all days (every day box) and i verify, if the date (registered on create document) is > that Today date, then, i must delete the document from firestore since it;

How to set epoch in Firestore using server time

I'm trying to set the epoch when data is created in Firestore. I'm looking to get some similar result to what is done in the real-time database, using ServerValue.TIMESTAMP.
I don't want to set it by using the device time System.getCurrentMillis because that time can be changed by the user.
According to docs an update needs to be done, the problem with that is the format. This is my code:
Map<String, Object> map = new HashMap<>();
map.put("timestamp", FieldValue.serverTimestamp());
reference.update(map);
And this is the result in the Firebase web console:
I was very surprised it is in spanish, which could be useful in some situations but epoch is what I'm chasing. Try to see the bright side and stick with it and thought that I was seeing the web in spanish, so I changed the language in the footer selector, it didn't change. On this point I'm assuming is set in the project language.
Back to the epoch attempt. Considering my project is using the real-time database as well, I try to set it in that way:
Map<String, Object> map = new HashMap<>();
map.put("timestamp", ServerValue.TIMESTAMP);
reference.update(map);
It did upload something, but it was just nonsense.
I think using epoch as the server-side timestamp is a better standard approach, after that every client can transform it to the user convenience and locale.
Can the epoch by set as server value in Firestore?
UPDATE
The answer marked as correct lead me to some interesting findings that I would like to share, so others in the same situation can benefit from:
There is no need to set the epoch because of the FieldValue.serverTimestamp() it is a date object handled by the database, what we see in the console is just a friendly way to show it.
Since FieldValue.serverTimestamp() is a date object it can be sort as any other timestamp could be, if you add orderBy("timestamp", Query.Direction.DESCENDING) to your query (or Query.Direction.ASCENDING) it will sort the results correctly.
And regarding to a the #34m0 comment, that is right, clients should not take care of the logic for setting the creation time, but it should be done in Functions.
The object that results from setting a Firestore field with FieldValue.serverTimestamp() is an instance of java.util.Date. When you later read the value, you can get the epoch time using getTime().
As an example, for a document created like this:
Map<String, Object> doc = new HashMap<>();
doc.put("timestamp", FieldValue.serverTimestamp());
The resulting value can be read like this:
docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot snapshot = task.getResult();
if (snapshot != null) {
Map<String,Object> map = snapshot.getData();
Date date = (Date) map.get("timestamp");
Log.d(TAG, "date=" + date);
Log.d(TAG, "time=" + date.getTime());
} else {
Log.d(TAG, "No such document");
}
} else {
Log.d(TAG, "get() failed with ", task.getException());
}
}
});

Delete a set of firebase data automatically after assigned time has passed

I have some data in FirebaseDatabase in which every data set has two properties: startTime and endTime.
Here's the data-structure:
app
-ref
-uniqueID1
-key: value
-startTime: 1488849333
-endTime: 1488853842
-key: value
-uniqueID2
-key: value
-startTime: 1488850198
-endTime: 1488853802
-key: value
What I want is to deleted the data set when the endTime has passed automatically or when the user opens the app.
I have done some research on this topic and found this, but this doesn't seems helpful to me.
How can I remove the datasets whose endTime has passed?
This looks like a similar answere but you seem not to understand the answer. So here is how to do it.
Since what matters is the end time only we are going to monitor when it has passed. To do this, we get the current time
Date().getTime();
and check whether its greater than the end time(if it is, it means that the end time has passed)
final DatabaseReference currentRef = adapter.getRef(position);
currentRef.child("endTime").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
long time = System.currentTimeMillis(); //get time in millis
long end = Long.parseLong( dataSnapshot.getValue().toString()); //get the end time from firebase database
//convert to int
int timenow = (int) time;
int endtime = (int) end;
//check if the endtime has been reached
if (end < time){
currentRef.removeValue(); //remove the entry
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
i have implemented that code when the item i want to remove is clicked. so the adapter is from a listview.
Thanks, i hope it helps

Categories

Resources