Android Firebase negative ServerValue.TIMESTAMP for ordering - android

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 .

Related

How to sort a list in Flutter

I am building a list in flutter and need to sort it by date by showing the most recent timestamp first.
The list is created from a json like the one below:
[
{
"id":100,
"timestamp":"2021-02-02T15:15:11Z",
"name":"Entry1"
},
{
"id":101,
"timestamp":"2021-03-02T11:12:56Z",
"name":"Entry2"
}
]
Once the json is fetched with the fetchEntries function, I'd like to sort the list. This is my code:
class Values extends Object {
int id;
String timestamp;
String name;
Values(
{this.id,
this.timestamp,
this.name});
Values.fromJson(Map<String, dynamic> json) {
id = json["id"];
timestamp = json["timestamp"];
name = json["name"];
}
}
List<Values> _myList = [];
fetchReport() {
_timer = new Timer.periodic(Duration(seconds: 1), (timer) {
fetchEntries(dates.id.toString(), dates.from, dates.to)
.then((value) => {
_myList.addAll(value),
_postsController.add(1),
setState(() {})
});
_timer.cancel();
});
//This is the sort code that doesn't work
_myList.sort((a,b)=> a.timestamp.compareTo(b.timestamp));
}
Alternatively, the list can be sorted by id in decreasing order but the timestamp method is preferred. Any suggestions how to do it properly?
It is better to parse time after fetch data.
_myList.sort((a,b) {
DateFormat formatter = DateFormat("yyyy-MM-ddTHH:mm:ssZ");
DateTime aTime = formatter.parse(a["timestamp"]);
DateTime bTime = formatter.parse(b["timestamp"]);
return aTime.compareTo(bTime);
//return bTime.compareTo(aTime);
}
I think that issue why sorting does not work is that _myList.sort function is called before _myList is filled with data. The reason of that is that _myList is populated in future (when callback of fetchEntires(...).then) is called, while sort function is called right after timer is created (after Timer.periodic constructor).
In order to fix that you need to move _myList.sort to callback just after list is populated with data.
Regarding sorting itself.. While it should work comparing date in the format of your example, I would rather parse time to milliseconds and then compare those instead. Reason is that once you change date format to different one, like 'dd-MM-yyyy' sorting will be broken.

How to Write Data Into Firebase Realtime Database with Cloud Functions when new Data is added to a Specific Child

I have the following realtime database schema:
schema
I'm working on a social app where a user can like another user. When the user clicks on the like button, a new entry will be added to myLikes->userId list
MyLike myLike = new MyLike(userId, System.currentTimeMillis();
FirebaseDatabase.getInstance().getReference().child("myLikes").child(userId).child(System.currentTimeMillis()).setValue(myLike);
When the new entry is completed, the cloud function gets triggered to write a new entry in whoLikedMe>userId list for the other User who has been liked.
exports.whoLikedMe = functions.database.ref('/myLikes/{userId}')
.onWrite((change, context) => {
// Only edit data when it is first created.
if (change.before.exists()) {
return null;
}
// Exit when the data is deleted.
if (!change.after.exists()) {
return null;
}
// Grab the current value of what was written to the Realtime Database.
const data2 = change.after.val();
const likedDate = data2.date;
const myUserId = data2.I_Liked_UserId;
var likedMe = {
date: likedDate,
Who_Liked_Me_UserId: myUserId,
}
//get the current date in millis
var hrTime = process.hrtime();
const dateMillis = hrTime[0];
return admin.database().ref('/WholikedMe/'+myUserId+'/'+hrTime[0]).set(likedMe);
});
The function gets triggered ok but no entries are inserted into the realtime database. What I'm doing wrong?
EDIT:
When I changed:
exports.whoLikedMe = functions.database.ref('/myLikes/{userId}')
with
exports.whoLikedMe = functions.database.ref('/myLikes/{userId}/915170400000')
(which adds the hardcoded timestamp to the path) all works fine. The problem is that the timestamp is constantly changing. any idea how to accomplish this with the timestamp?
You're using wildcard syntax (curly braces) in the following line:
return change.after.ref('/WholikedMe/{myUserId}/{hrTime[0]}').set(likeMe)
That syntax does not apply to a set statement. You need to use :
return change.after.ref('/WholikedMe/' + myUserId + '/' + hrTime[0]).set(likeMe)
... I think, doing this on my phone so can't double check. :-)
I figure d out. In addition to the syntax correction suggested by #GrahamD I had to change
exports.whoLikedMe = functions.database.ref('/myLikes/{userId}')
with
exports.whoLikedMe = functions.database.ref('/myLikes/{userId}/{timestamp')
and now all is working fine.

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());
}
}
});

How to add array value in Firebase

I want to add some certain data to a Firebase as arrays. Example:
groups : ['a','b','c']
How can I add and read data in Firebase from Android?
When you have a structure like that, you actually shouldn't be using an array to model it. It seems much more like a set in my eyes.
In the Firebase Database sets are best modeled as keys, since that automatically guarantees that items are unique. So your structure then becomes:
groups: {
"a": true,
"b": true,
"c": true
}
The true values are just markers, since Firebase won't allow you to store keys without a value.
Now to add a group to this, you'd use Firebase's setValue() function:
DatabaseReference root = FirebaseDatabase.getInstance().reference();
DatabaseReference groupsRef = root.child("groups");
groupsRef.child("d").setValue(true);
From the documentation:
setValue() - Record or change exists values
If you want to only append datas, you can to use updateChildren().
In Java, if we know that the data is array-like, it can be cast as a List:
Firebase julieRef = new Firebase("https://SampleChat.firebaseIO-demo.com/users/julie/");
julieRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
GenericTypeIndicator<List<String>> t = new GenericTypeIndicator?<List<String>>() {};
List messages = snapshot.getValue(t);
if( messages === null ) {
System.out.println('No messages');
}
else {
System.out.println("The first message is: " + messages.get(0) );
}
}
// onCancelled...
});
Check this best practices post from the Firebase Blog.

Querying Firebase based on ServerValue.TIMESTAMP

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);

Categories

Resources