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
Related
I got a list of objects. I need to go through the list and for each item, I need to set unique timestamp value. How I can implement it?
Now if I understand right the computation makes in less than 1ms so in logs I see weird values.
Here is an example of the code.
List<String> list = new ArrayList<>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
list.add("six");
list.add("seven");
list.add("eight");
list.add("nine");
list.add("ten");
for (String s : list) {
Long tsLong = System.currentTimeMillis() / 1000;
String ts = tsLong.toString();
Log.d("timestamp", s + ts);
}
Logs instead of 10 values it shows 2 equal values
D/timestamp: 1584554340
D/timestamp: 1584554340
Since the iteration goes very fast. I decided to get a timestamp in the beginning of iteration and just make +1 with each loop.
List<String> list = new ArrayList<>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
list.add("six");
list.add("seven");
list.add("eight");
list.add("nine");
list.add("ten");
Long tsLong = System.currentTimeMillis() / 1000;
for (String s : list) {
Log.d("timestamp", tsLong.toString());
tsLong++;
}
In this case, each item got a unique timestamp. That implementation was needed to fill EXISTING db with objects who does not have timestamp value but need to have for present usage. So with help of that I will add unique timestamp to each user which i have in DB.
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;
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.
How to modify realm result data when dealing with date and time? ASCENDING and DESCENDING is not enough for me.
Say for example I am getting a task thats within an hour of due?
RealmResults<Task> tmp = realm.where(Task.class).findAll();
for (final Task task : tmp) {
String dateFormat = Utility.TIMEFORMAT;
String current = "2:30:00 PM";
Date currentTime = new Date(task.gettime());
//currentTime = new SimpleDateFormat(dateFormat).parse(current);
if( isIncomingWithInHour(currentTime, calendar)){
realmresult.add(tmp) /// this result in error.
}
}
As you can see ASCENDING and DESCENDING wont work in this kind of sorting. Anyway to give the reamlResult back to the adapter? Realmresult has an onchangeListener and I want to use that.
Instead of
RealmResults<Task> tmp = realm.where(Task.class).findAll();
You can do something like
RealmResults<Task> tasksInOneHour = realm.where(Task.class)
.greaterThanOrEqualTo("time", startTime)
.lowerThan("time", endTime)
.findAll();
Time constraints - while it is not clear in field of which type you store time in your Task class i'll provide an answer for a long field (and if it's not long, i suggest you to use it). Realm has a nice query picking capabilities, which we can make a use of:
RealmResults <Task> tasksInOneHourList =
realm.where(Task.class).between("TIME_LONG_FIELD_NAME", CURRENT_TIME, CURRENT_TIME + HOUR_IN_MILLIS).findAll();
Notify adapter - you can update adapter data as the following:
tasksInOneHourList.addChangeListener(new RealmChangeListener<RealmResults<Task>>() {
#Override
public void onChange(RealmResults<Task> tasks) {
adapter.notifyDataSetChanged();
}
});
I am making and application that show a first screen with a bunch of randomly picked data from a node in Firebase database.
To present user with different data every time is kind of important for my application
Is there anyway to achieve this in native Android, all snapshots are of same model
There is no direct way provided by firebase database but you can do this using Collections.shuffle()
What i did was,Take the snapshot and store it in an arraylist.
private ArrayList<Integer> array=new ArrayList<>();
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot imageSnapshot : dataSnapshot.getChildren()) {
MyClass myclass = imageSnapshot.getValue(MyClass.class);
array.add(myclass.someFunction());
}
}
Then call the shuffle method on this array list.
Collections.shuffle(array); // randomize the arraylist
Now you can do whatever you want with this randomized arraylist.
Don't think there is a way to randomly grab data from the Firebase database as all queries that you can construct end up being deterministic in some way, either based on the generated push ids (which in turn are based on time) or some other key ordered lexicographically. I think the best way would be to grab a list of data from a node and randomly choose the data client side.
There actually is a possibility to do that without Loading the whole list client side. First you have to generate a numeric id either as child id or as an extra node.
That how your database would look like:
notes:
-KXe8LJJzczEJs3YYwRe
numericid : 001
-KXeePWrWBXvpw4g9n0p
numericid : 002
or
notes:
001
002
to create the numbers as String you can use DecimalFormat
String newint = new DecimalFormat("000").format(oldint);
Now you can get the children count in your valueeventlistener an use Math.random() to get a random child, e.g. for the second Database Design
FirebaseDatabase().getInstance().getReference().child("notes").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Long childrencount = dataSnapshot.getChildrenCount();
if(childrencount.equals(0))return;
int random = getRandomInteger(safeLongToInt(childrencount), 1);
String selectedchild = new DecimalFormat("000").format(random);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
You also need to add these safeLongtoInt and getRandomInteger
public static int getRandomInteger(int maximum, int minimum){
return ((int) (Math.random()*(maximum - minimum))) + minimum;
}
public static int safeLongToInt(long l) {
if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) {
throw new IllegalArgumentException
(l + " cannot be cast to int without changing its value.");
}
return (int) l;
}
selectedchild is your random child id.