Need help in Firebase query for this scenario - android

I have DB structure as
and my code query is
quesRef = myRef.child("questions").orderByChild("timestamp").endAt("120");
Ideally as per my understanding all the values whose timestamp is less than 120 should get return, but in my case, almost all the questions are getting returned.
Am I doing something wrong ?

You are querying to an ending value of the string "120" instead of the number 120.
Instead, it should read:
quesRef = myRef.child("questions").orderByChild("timestamp").endAt(120);
I'm not sure why the timestamp would be as low as 120 anyway, but perhaps that's just for testing purposes?

Related

How can I store the user number like this (1,2,3...)?

When a new user signs up, there should be a property named userNo. which should be increased by 1 in each document, so that it would be easy to pick random users from db using that userNo. Basically, like each document holds a User number similar to Uid but not like Afhghdfh4hk545, it should be like userNo.23 and so one. If a new user signs up its userNo. should be 24. Here is what I have tried.
Stream dummy =
await FirebaseFirestore.instance.collection('users').snapshots();
var doclength = await dummy.length;
var userNo = (dummy == null || dummy == 0) ? 1 : doclength;
FirebaseFirestore.instance
.collection('users')
.doc(currentUser.uid)
.update({'userNo': userNo});
Alright, you'll need a "meta document" that has a field called something like "next_user_number".
Upon creating a new user, you check the number on that field and use it as the "UserNo" for the newest user.
And after that, you increase the "next_user_number" in the "meta document" by 1. (here you want to use FieldValue increment - search for "firestore increment" for how to do it.)
But... to be absolutely sure this will work even in cases when two users are signing up at the same time or other error-prone cases, make sure you use a "batch write".
A batch write means that both operations are done together, so both incrementing the "next_user_number" and creating the new user with the right "UserNo" number are going to be accurate. (search for "firesotre batch write" to learn more).
Okay, I solved it after drinking mugs of coffee. To all of the future visitors you can get the exact length of documents in that particular collection and then use then keyword and extract the value and store it in int variable. Then you can use extractedValue.size as the userNo.

Firebase CompareTo Method

i am trying to use compareTo method based on firebase docs to get how long ago was the database entry created.
https://firebase.google.com/docs/reference/android/com/google/firebase/Timestamp
I am trying to do something like this
var postedAgo = myEntry.dateCreated.compareTo(firebase.database.ServerValue.TIMESTAMP);
myEntry.dateCreated is stored TIMESTAMP, so all i got in my db is numerical value. I hope thats right. But the problem is when i log this it says that compareTo is not a function.
I am obviously doing something wrong, but i cant find almost anything on compareTo beyond the documentation. I wonder if anyone is even using it.
Thanks
Luke
The Firebase Database ServerValue.TIMESTAMP is not an actual value of a timestamp, but a so-called marker value that the server recognized (and then replaces by the current timestamp when writing to the database). Because of this, you cannot use ServerValue.TIMESTAMP in pure client-side operations.
If you want to determine how long ago a node was created, you'd take the timestamp from that node and subtract it from the current timestamp. So if myEntry.dateCreated is a timestamp that was written with ServerValue.TIMESTAMP, you could do:
System.currentTimeMillis() - myEntry.dateCreated

Firebase Query - how to order by a separate field?

I'm working with an Android App that functions as an instant messaging service, and I'm at the point of pulling the message data through into a RecyclerView. I have my Firebase Query object returning all the messages that match the id of the chat that has been loaded, this is done like so:
Query qChatMessages = mDbRefMessages
.orderByChild("messageChat")
.equalTo(mChatId);
So far so good, and this is returning the collection of messages that I expect. The problem is now that, upon passing them to the RecyclerView to be displayed, they come out in the inverse order of how you would typically expect an instant messenger to display, so the messages are actually getting older as you scroll down the chat.
My message nodes in the database all have a messageTimestamp field associated with them, so this is what I would want to sort the data by. The problem is that I don't seem to be able to find a way of ordering the data by any field other than the one that I'm querying on, or getting the results back from Firebase and subsequently ordering them.
Does anyone know how I can work around this, or if there's some Firebase capabilities I'm not aware of?
Thanks in advance,
Mark
The easiest way is to store an extra piece of data in your message nodes which is the epoch time multiplied by -1: this way you can sort on this field and the query will return the right order.
See this post on how to get the epoch time: how to get the number of seconds passed since 1970 for a date value?
However, note that with your current data structure, you will encounter a problem: you will need to sort on this new data (e.g. with .orderByChild("messageCreationTime")) AND filter for a given mChatId (e.g. with equalTo(mChatId)), which is not possible.
So, you would have to re-structure your database (if this is possible) like this:
- messages
- mChatId
- messageUniqueID <- most probably auto-generated by Firebase
- messageTitle: ....
- messageCreationTime: -1525857044
And you would query by:
Query qChatMessages = databaseReference.child("messages").child(mChatId)
.orderByChild("messageCreationTime");

Maintaining dynamically computed values in firebase

I have a simple firebase database: /rides is a list of simple objects like this
{
car: "Toyota"
minutes: 15
}
and I need to display sum of minutes of all the rides. The obvious solution is to load all the rides and calculate the sum. But if I have several hundreds of rides this is very slow, up to several seconds.
So it seems I have to maintain a separate field /totalMinutesin the database for this. But thus I will have to manually update /totalMinutes every time I add/remove/change a ride. Anyway this is not a big deal of work.
But what if I need to calculate total minutes only for a subset of rides? For instance only for "Toyota" cars or "Ford" cars? Manual maintaining /totalMinutesFord, /totalMinutesToyota now doesn't seem so easy.
So what is the correct way to maintain such dynamic values in firebase?
Firebase has no way to get automatically calculate values based on the data in your database.
So your two options are:
calculate the value whenever you update the data
retrieve all the data and calculate the value on the client
You already (wisely) decided that retrieving all data is not a good idea. Your users will be grateful for that.
So that leaves calculating the derived values whenever you update the data of a ride. I'm not sure why doing that for multiple values would be more difficult than doing it for a single value. It may be more code, but it's pretty much the same code:
var ride = { car: "Toyota", minutes: 15 };
ref = new Firebase('https://yours.firebaseio.com/');
ref.child('rides').push(ride);
ref.child('totalMinutes').transaction(function(current_value) {
return (current_value || 0) + ride.minutes;
});
ref.child('totalMinutes'+ride.car).transaction(function(current_value) {
return (current_value || 0) + ride.minutes;
})

Android - Do I need to sort a collection for min and max?

I came here (SO) a few days ago to research how to get the min and max from a collection in Android and found a solution to the effect of the following (sorry haven't got a link to the actual answer I used):
Max = (TextView)findViewById(R.id.Max);
Collections.sort(list);
Max.setText(String.format("%.2f", Collections.max(list)));
My question is do I actually need to sort the list before pulling the min/max value? I have tried running the code without sorting the list and it seems to work OK. I am just worried because the answer I used definitely sorted the list first so I assume there must be a reason, I just don't know what it is!
In addition #BobbyDigital's answer who corectly points out the th method iterates over the complete list, I would just like to mention that the result of using the max function might depend on the type of the list elements. If you see the doc , it says that
Returns the maximum element of the given collection, according to the natural ordering of its elements.
If you see Why does Collections.max() not return actual max value for a Collection of String? question, the person used a list of Strings. On extracting max using the abve number he did not get the max number as it was returning the value that's the largest lexicographically. So, just to mention his code:
ArrayList<String> dirNo = new ArrayList<String>();
dirNo.add("1");
dirNo.add("2");
dirNo.add("3");
dirNo.add("4");
dirNo.add("5");
dirNo.add("6");
dirNo.add("7");
dirNo.add("8");
dirNo.add("9");
dirNo.add("10");
dirNo.add("11");
System.out.println("max : " + Integer.parseInt(Collections.max(dirNo))
+ "");
The above code gave 9 as the answer. So be careful while using it. You mgiht want to convert everything to Integer etc based on your needs.
P.S: The example is from the question mentioned and the answer is inspired from this answer by NPE on same question.
No it doesn't have to be sorted. The method iterates over the entire collection.
See the Java docs for the method!

Categories

Resources