I have a FireBase back end that has a time stamp like so... there are many of these nodes that are objects that have been pushed.
each node has a time stamp set with ServerValue.TIMESTAMP.
in data model class setting server time
private HashMap<String, Object> timestampCreated;
//set time stamp in constructor when new obj is created
public DataModel(...){
// TIME STAMP
HashMap<String, Object> timestampCreatedObj = new HashMap<String, Object>();
timestampCreatedObj.put("date", ServerValue.TIMESTAMP);
this.timestampCreated = timestampCreatedObj;
}
//getting timestamp
public HashMap<String, Object> getTimestampCreated(){
return timestampCreated;
}
#Exclude
public long getTimestampCreatedLong(){
return (long)timestampCreated.get("date");
}
The above all works fine for insertion in DB and i can retrieve the time.
in another class i want to set a query on a FirebaseListAdapter
setting the query lets say for showing items in last 5 days.
long daysInpast= new Date().getTime() - TimeUnit.MILLISECONDS.convert(5, TimeUnit.DAYS);
Then i set up query
Query queryDays= mDatabaseQuery.child("timestampCreated").orderByChild("date").endAt(daysInpast);
final FirebaseListAdapter<myData> adapterQuery = new FirebaseListAdapter<myData>
(getActivity(), myData.class, R.layout.list_item, queryDays) {//do stuff}
Its my query I'm not sure of, my list is returning empty, If i just use my FirebaseListAdapter without the query passing the DB reference my list populates as expected. I suspect its how data is laid out? he fact my times tap is in a subnode is that an issue?
I've tried just using
Query queryDays= mDatabaseQuery.orderByChild("date").endAt(daysInpast);
also but no vail
any help appreciated
You need to run a query on the location above the children that you want returned, which looks to be the root of your database (please don't post pictures with blurred out text, post the actual JSON as text next time).
If indeed you need the level under the root of your database, you can query for the date with:
DatabaseReference root = FirebaseDatabase.getInstance().getReference();
Query query = root.orderByChild("timestampCreated/date").endAt(daysInPast);
Related
May I ask if there is any implementation to collect the time when the first data is updated. For example, there is a queue function in my app. When an user has taken the queue ticket, Firebase will then be updated.
Therefore, I would like to know the time that the first user in the queue.
Is there any code for this in Android Studio? Many thanks!!
The Firebase Database does not store metadata (informations like the timestamp) for CRUD operations that are performed. Because of that, you need to store this kind of data yourself by creating your own mechanism.
In fact, you need to create a new field for each child you want to trace and change the value of the timestamp every time a action is performed. The best practice within a Firebase database is to save your data as a timestamp using: ServerValue.TIMESTAMP.
Note, that when you are saving the timestamp, you are saving as a Map and when you are retrieving, you are retrieving it as a long.
To set the timestamp, I recommend you to use the following code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
Map<String, Object> map = new HashMap<>();
map.put("timestamp", ServerValue.TIMESTAMP);
rootRef.child("yourNode").updateChildren(map);
To get you data back, I recommend you using the following method:
public static String getTimeDate(long timeStamp){
try{
DateFormat dateFormat = getDateTimeInstance();
Date netDate = (new Date(timeStamp));
return dateFormat.format(netDate);
} catch(Exception e) {
return "date";
}
}
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());
}
}
});
I have a list item within AWS NoSQL DB.
I want to add a String value to the end of that list. My code is the following:
HashMap<String, AttributeValue> primaryKey = new HashMap<>();
AttributeValue key = new AttributeValue()
.withS(Array1[x]);
AttributeValue range = new AttributeValue()
.withS(Array2[x]);
primaryKey.put("XXXXX", key);
primaryKey.put("XXXXX", range);
try {
UpdateItemRequest request = new UpdateItemRequest()
.withTableName("XXXXXXXXXXXXXXXX")
.withKey(primaryKey)
.addAttributeUpdatesEntry(
"groups", new AttributeValueUpdate()
.withValue(new AttributeValue().withS(groupID))
.withAction(AttributeAction.ADD));
dynamoDBClient.updateItem(request);
Unsurprisingly this just overwrites the entire list in the AWS DB with the string rather than adding a new element to the list.
Is there anyway to do this without having to download the whole list, adding the string and then re-uploading? Would be allot cleaner to just ask that a new element is added to the end of the list.
Figured it out if anyone is having a similar issue.
Rather than trying to add an element to the "groups" field which is a list I changed the field in DynamoDB to a string set and adjusted the code as follows:
try {
UpdateItemRequest request = new UpdateItemRequest()
.withTableName("XXXXXXXXXXX")
.withKey(primaryKey)
.addAttributeUpdatesEntry(
"groups", new AttributeValueUpdate()
.withValue(new AttributeValue().withSS(groupID))
.withAction(AttributeAction.ADD));
dynamoDBClient.updateItem(request);
This now adds a new element to the end of the string set
I believe you're are actually looking for this:
UpdateItemRequest request = new UpdateItemRequest();
request.setTableName("myTableName");
request.setKey(Collections.singletonMap("hashkey",
new AttributeValue().withS("my_key")));
request.setUpdateExpression("list_append(:prepend_value, my_list)");
request.setExpressionAttributeValues(
Collections.singletonMap(":prepend_value",
new AttributeValue().withN("1"))
);
dynamodb.updateItem(request);
Example taken from: How to update a Map or a List on AWS DynamoDB document API?
I use ServerValue.TIMESTAMP in Firebase for ordering in query. I set timestamp in my model class to dats for example 1494325636954.
public Attendance(String usico) {
this.usico = usico;
HashMap<String, Object> datsObj = new HashMap<String, Object>();
datsObj.put("date", ServerValue.TIMESTAMP);
this.dats = datsObj;
}
How can I set to datt negative ServerValue.TIMESTAMP for example -1494325636954 ?
You can create a Firebase Function to update the value to be negative, while maintaining the server accurate timestamp.
exports.makeNegativeTimestamp = functions.database.ref('/posts/{postID}/date').onWrite(event => {
// get the timestamp from the DeltaSnapshot
const timestamp = event.data.val();
// ensure that the timestamp is a number
if (isNaN(timestamp)) { return; }
// only make negative if it's currently positive
if (timestamp >= 0) {
// returns a promise
return event.data.adminRef.set(timestamp * -1);
}
});
Use timeStamp in other cases but when it comes to firebase you don't need to go all the to convert timeStamp to negative for just sorting, my way is put decrementing long or int whenever child is added (inside child's property) then use that as a sorting method, this will simplify lot of time if you care only about order .
I am showing some posts (created by the users) in an activity using a custom adapter. In the constructor of the custom adapter, I am using the following code to get the query result.
ParseQuery query = new ParseQuery("Post");
query.whereWithinMiles("location_point", my_point, 500);
query.whereGreaterThan("expire_date", new Date());
return query;
The target is - the user can set an expire date with each post so that the post will no longer be visible after the expiration. I am trying to compare the expire_date column with current time for checking if the post is expired or not.
The line query.whereGreaterThan("expire_date", new Date()); was added later. All the previously created rows has a null value in the expire_date column.
So each time I run the query, all the rows that has a date object in expire_date column are being checked according to the condition. The rows having a null value in expire_date column are never returned.
Note: The expire_date column is not a mandatory field (user can choose to leave it empty during creating a post).
Yes, I can set a default date for all the empty/null fields to compare with the expire date. But I was curious to know if there is a way so that I can either return all the rows having a null value or compare the current time with a null object with the whereGreaterThan condition?
ParseQuery notExpiredPosts = new ParseQuery("Post");
query.whereGreaterThan("expire_date", new Date());
ParseQuery noExpiredDate = new ParseQuery("Post");
query.doesNotExist("expire_date");
ParseQuery expiredDateQuery = ParseQuery.or(notExpiredPosts, noExpiredDate);
ParseQuery query = new ParseQuery("Post");
query.whereWithinMiles("location_point", my_point, 500);
query.whereMatchesKeyInQuery("objectId", "objectId", expiredDateQuery);
return query;
[(NotExpiredPost || NoExpiredDate) & (location_point within 500 mile)]
This is what you want, isn't it?
Hope this helps :)