I am trying to query items in my firebase database based on an attribute value.
Here is my structure:
Here is my POJO object:
public class LapTime {
private int vehicleType;
private String track;
private String user;
private int time;
}
And here is my query code:
mDatabase.child("lap-time").orderByChild("track").equalTo(mTrackUuid).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
time = dataSnapshot.getValue(LapTime.class).getTime() + "ms");
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
My problem is that the datasnapshot I get back has for root lap-time and not the UUID, thus the getValue(LapTime.class) give me an empty object...
Here is the datasnapshot I get:
DataSnapshot { key = lap-time, value = {-KXwSxD0GYVC6awV8abw={track=-KXwSxCeV2Ib4Gt4pvjy, time=105000, vehicle-type=0, user=ZQKwPfRF0mVL5jAO7FaSPcsF7t42}} }
And this is what I would like to get:
DataSnapshot { key = -KXwSxD0GYVC6awV8abw, value ={track=-KXwSxCeV2Ib4Gt4pvjy, time=105000, vehicle-type=0, user=ZQKwPfRF0mVL5jAO7FaSPcsF7t42}} }
How can I do that?
Since your query code can actually have more than one result you should be calling dataSnapshot.getChildren() and iterating through the children to get the result you're looking for. Particularly, mDatabase.child("lap-time").orderByChild("track").equalTo(mTrackUuid) is a query that could have multiple results since there could be a situation where multiple LapTime objects could have a track that points to the same mTrackUuid. Now, to get the result of the log you posted you need to construct a the query like so: mDatabase.child("lap-time").child("-KXwSxD0GYVC6awV8abw"). Notice how the orderByChild/equalTo queries are gone since those result in a conditional query that may return a list of data instead of a singular value.
Related
I am trying to retrieve a list that is on a child that starts with something. Below is a sample of data in my Firebase realtime database:
In the image, I want to retrieve all data that starts with the keyword "jsonmat".
I am using thee code below but it always return null:
DatabaseReference db = FirebaseDatabase.getInstance().getReference()
.child("Events");
db.startAt("jsonmat").addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.i("events", dataSnapshot.toString());
for (DataSnapshot data : dataSnapshot.getChildren()) {
// here the user will have the specified email only
}
}
#Override
public void onCancelled(DatabaseError databaseError){
Log.i("MyApp", "getUser:onCancelled", databaseError.toException());
}
});
What you're trying to do isn't possible. You can't order/filter of a nested key, only on direct child keys (-M...) and on nested values (active: true).
Typically you'll want to create a new top-level node, where you store the keys you're searching for, and then the push keys for each matching nested node:
"category_things": {
"jsonmat_jsonmat": {
"-M62....uYgB": true,
"-M62....2-eO": true
}
}
Also see:
Firebase Query Double Nested
My original, but wrong answer is below...
If you use startAt without specifying an orderBy... clause, the data will be ordered by priority. This priority is a left-over from before Firebase supported ordering on specific properties, so mostly it means that you must call an orderBy... method before filtering.
So:
DatabaseReference db = FirebaseDatabase.getInstance().getReference().child("Events");
db.orderByKey().startAt("jsonmat").addListenerForSingleValueEvent(new ValueEventListener() {
...
What you can do for your case, is to loop 2 times over the children of the node Events:
//the reference to the node Events
DatabaseReference db = FirebaseDatabase.getInstance().getReference().child("Events");
db.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//loop 1
for (DataSnapshot data : dataSnapshot.getChildren()) {
//loop2
for (DataSnapshot dataTwo : data.getChildren()) {
//get the key
String key = dataTwo.getKey();
if(key.startsWith("jsonmat")){
//we got a matching key so extract the data and maybe put them in a list
boolean active = dataTwo.child("active").getValue(Boolean.class);
int bet = dataTwo.child("bet").getValue(Integer.class);
String challenger = dataTwo.child("challenger").getValue(String.class);
String competitor = dataTwo.child("competitor").getValue(String.class);
String game = dataTwo.child("game").getValue(String.class);
............
............
............
}else{
//we didn't get a match
}
}//end loop2
}//end loop1
}
#Override
public void onCancelled(DatabaseError databaseError){
Log.i("MyApp", "getUser:onCancelled", databaseError.toException());
}
});
I am storing user details 'firstname' and 'lastname' in UserNode. But when i want to retrieve that details then no data is being retrieved. I tried almost all solutions on the internet but nothing solved my problem. Here is my code for retrieving data of the current user:
FirebaseUser userr = FirebaseAuth.getInstance().getCurrentUser();
if (userr != null) {
String name = userr.getDisplayName();
Log.e("value", name);
}
but it says "println needs a message"
I also tried with this but nothing happened:
DatabaseReference DataRef;
DataRef = FirebaseDatabase.getInstance().getReference().child("UserNode");
DataRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String acctname = (String)dataSnapshot.child("firstname").getValue();
Log.e("name", acctname);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
]1
Please help me I am stuck with it
You're reading a collection of user with a ValueEventListener. As the [Firebase documentation for reading lists with a value event](Listen for value events) explains:
While using a ChildEventListener is the recommended way to read lists of data, there are situations where attaching a ValueEventListener to a list reference is useful.
Attaching a ValueEventListener to a list of data will return the entire list of data as a single DataSnapshot, which you can then loop over to access individual children.
Even when there is only a single [child node], the snapshot is still a list; it just contains a single item. To access the item, you need to loop over the result.
So in your code:
DatabaseReference DataRef;
DataRef = FirebaseDatabase.getInstance().getReference().child("UserNode");
DataRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
String acctname = (String)childSnapshot.child("firstname").getValue();
Log.i("name", acctname);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
Using FirebaseUser:
FirebaseUser implements UserInfo and in UserInfo's getDisplayName() documentation says
Returns the user's display name, if available.
So, it is possible that FirebaseUser.getDisplayName() return null when display name is not set. In that case Log.e() receives null as message and therefore prints println needs a message
Using your own structure:
Instead of using type conversion use getValue(Class<T>) like so:
String acctname = dataSnapshot.child("firstname").getValue(String.class);
Please, read how to retrieve data from firebase. I think you have a problem because you don't have Class Model.
Your steps:
Create model UserModel with firstname and lastname field
Use listener (example from docs):
// Attach a listener to read the data at our posts reference
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Post post = dataSnapshot.getValue(Post.class);
System.out.println(post);
}
#Override
public void onCancelled(DatabaseError databaseError) {
System.out.println("The read failed: " + databaseError.getCode());
}
});
See other answers: How to retrieve data from one single userID Firebase Android and retrieving data from firebase android
I'm trying to display the "loc" of a part if its part number I given.
Here is what the data structure looks like:
{
"parts":{
"14521845": { "name":"TOOL EC160B/EC180B/EC210B/EC240", "loc":"EXC1", "sloc":"B3EGU01C03"},
"12829050": { "name":"SWITCH; IGNITION SWITCH", "loc":"PS01", "sloc":"85-06-013"},
"12829050": { "name":"SWITCH; IGNITION SWITCH", "loc":"COM1", "sloc":"B3RGK03D06"},
"20044893": { "name":"PARTS CATALOG_ENG_SPA_FRE_GER_KOR_EC210D", "loc":"EXC1", "sloc":"B3EGT01B02"}
}
}
Activity Code:
FirebaseDatabase firebaseDatabase=FirebaseDatabase.getInstance();
DatabaseReference databaseReference =firebaseDatabase.getReference("parts/"+curP);
databaseReference.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Products data=dataSnapshot.getValue(Products.class);
Log.i("",String.valueOf(data.getLoc()));
}
getLoc is the getter function for the Product class, and it returns the corresponding "loc" for the given curP. curP denoted the child values in parts.
The logic seems right to me, but I am not getting an output. Where am I going wrong here?
try this
getReference("parts").child(curP).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Products data = dataSnapshot.getValue(Products.class);
Log.i("", String.valueOf(data.getLoc()));
}
});
The problem is that what you are getting in onChildAdded() is not a whole Product object as you expect it to be.
In your database reference you are targeting a specific Product ("parts/"+curP) but using a ChildEventListener. The children of a specific product node are name, loc and sloc, so the onChildAdded() will trigger several times, giving you each of these properties as a dataSnapshot separately.
The two patterns you might use to get whole Product objects are either:
add a ChildEventListener directly to the "parts" node and you will get each of the Products as a child of that node, or;
if you are adding a listener directly to the node of a particular product, use a ValueEventListener, to get the whole of that nodes entry as one dataSnapshot.
You can try to use ValueEventListener. If you want read data once so use the addListenerForSingleValueEvent method, something like this:
private void getFirebaseLocValue(int curP) {
FirebaseDatabase firebase = FirebaseDatabase.getInstance();
DatabaseReference mDatabase = firebase.getReference("parts");
mDatabase.child(Integer.toString(curP))
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.hasChildren()) {
Products data = dataSnapshot.getValue(Products.class);
Log.e("TAG", data.getLoc());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
Or you can use addValueEventListener and will get data with any changes. I really don't think that ChildEventListener is a good idea to retrieve data from Firebase.
I'm trying to implement firebase database in my app, but I'm having problems in retrieving data from multiple nodes at same time and updating the ui.
I'm storing all the Firebase methods in a separate class.
here is an example of one of the methods to retrieve one datum from a node.
public static void getTrainerCity(final Trainer trainer) {
dbref.child(USER_CITY).child(trainer.getId()).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
trainer.setCity(dataSnapshot.getValue(String.class));
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
Then, to get for example one complete trainer, I do
public static void getTrainer(final boolean isAthlete, final String trainerId, Trainer trainer) {
trainer.setId(trainerId);
getTrainerCity(trainer);
getTrainerName(trainer);
getTrainerAge(trainer);
getTrainerNumber(trainer);
getTrainerEmail(trainer);
getTrainerGym(trainer);
getTrainerPhoto(trainer);
getTrainerStudyDegree(trainer);
getTrainerDescription(trainer);
if(!isAthlete) {
getTrainerAthletes(trainer);
}
}
when I call this method in UI, I'm not getting the entire Trainer object in one shot as those methods don't run on the main thread. This means that the trainer is constantly updated. However, I want to notify the UI only when all fields of the object related to the method have been set (I have to populate lists and initialize user). How would you do this?
I thought about attaching listeners, but it seems like I need a tremendous amount of them. Thank you guys
EDIT: This is how Db is structured
It's scenarios like this where RxJava shines.....what you could do is wrap firebase queries in Observable.create() and then use something like RxJava zip operator to combine all the queries. The alternative (to be avoided if possible) is to nest all the queries which leads to dreaded callback hell
For example you might have something like following for getTrainerCity
public static Observable<String> getTrainerCity(int trainerId) {
return Observable.create(subscriber -> {
dbref.child(USER_CITY).child(trainerId).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String city = dataSnapshot.getValue(String.class);
subscriber.onNext(city);
subscriber.onCompleted();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
});
}
You should get trainer node first and then parse the fetched data.
I assume you have a Trainer node which contains all the info (city, name, age, ...)
public static void getTrainer(final Trainer trainer) {
dbref.child(trainer_node).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Trainer trainer = dataSnapshot.getValue(Trainer.class);
String name = trainer.getName();
String city = trainer.getCity();
int age = trainer.getAge();
.
.
.
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
EDIT:
Data structure maybe like this
-users_node
--user1
---id:userid
---name: username
---city:usercity
---email:useremail
---workouts
----workoutid1:true
----workoutid2:true
--user2
---id:..
-athletes_node
--user1:true
--user2:true
--userX:true
-workouts_node
--workoutid1
---workout details here
--workoutid2
---workout details here
I followed the documentation, but no matter what, I cannot figure out how to return all the objects from a single node. For example, I want to return a list of all company objects from the companies node. Once I have that list, I want to parse them all into JSON objects. This is my first time with a NoSQL database so I'm sure that I'm missing something small.
Currently I have:
DatabaseReference companiesRef = FirebaseDatabase.getInstance().getReference("12265");
companiesRef.child("companies").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.d("Count ", dataSnapshot.getChildren().toString());
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
But it just returns null for the value: DataSnapshot { key = companies, value = null }.
Here's my database:
You create your reference like this:
FirebaseDatabase.getInstance().getReference("12265");
This means that Firebase looks at the root of the database and returns the child 12265 from under there. It does not automatically search the tree for a node with a matching name.
So you'll need to specify the entire path:
FirebaseDatabase.getInstance().getReference("android/users/12265");
Don't add any parameters to your getReference() (let it go to the root of database) and then set the addListenerForSingleValueEvent. And you have not used getvalue() on you datasnapshot as well. Try this code:
DatabaseReference companiesRef = FirebaseDatabase.getInstance().getReference();
// this is the patch that I see from the image that you have attached.
companiesRef.child("telenotes").child("android").child("user").child("12265").child("companies").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.d("Count ", dataSnapshot.getChildren().getValue().toString());
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});