I am trying to use the firebase push() function, as I want to add a list off data to an allready existing list. The setValue() function overwrites existing data.
This is what I used to do:
DatabaseReference childref = mDatabase.child("users").child(uih.getUserData().getUsername()).child("answered_questions");
childref.setValue(getAnsweredQuestions(questionViewList));
This worked, but every time I use this function the data is overwritten and this is not what I want. I tried using the Push function as described by the firebase documation: https://firebase.google.com/docs/database/android/save-data
I am not sure I am doing it right, but it is not working. And this is when I tried to implement the push() function:
DatabaseReference childref = mDatabase.child("users").child(uih.getUserData().getUsername()).child("answered_questions");
String key = childref.push().getKey();
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put( key, questionViewList);
mDatabase.updateChildren(childUpdates);
The exception I get is:
com.google.firebase.database.DatabaseException: Failed to parse node with class class scrambled.nl.generationr.QuestionView
And this is weird, since I did not receive this error while doing the setValue method. Can anyone explain what I am doing wrong and how I should push a list to firebase?
edit:
What I can do is:
DatabaseReference childref = mDatabase.child("users").child(uih.getUserData().getUsername()).child("answered_questions");
childref.push().setValue(getAnsweredQuestions(questionViewList));
In added the push() here. This works, but instead of just increasing my list, i add another layer in my list so I actually get an array of arrays instead of a longer list.
See here the result:
Saving a List of AnsweredQuestion objects:
This assumes you've followed the rules when designing your AnsweredQuestion.class so that the Java object can be used to store data in Firebase. If you need guidance for that check under the "Basic write operations" heading for saving data in the documentation.
//List of AnsweredQuestions
List<AnsweredQuestion> mAllAnswers;
....
//create the database reference that points to the correct parent node
//where answeres are stored for each user
DatabaseReference ref = mDatabase.child("users").child(uih.getUserData().getUsername()).child("answered_questions");
//Iterate over your List of AnsweredQuestion objects and use push() along with setValue()
//to store a single AnsweredQuestion object to a unique location in your database.
for(AnsweredQuestion answer : mAllAnswers){
ref.push().setValue(answer);
}
Retrieve all answered questions for a user:
//create List to store AnsweredQuestion object
List<AnsweredQuestion> mAllAnswers = new ArrayList<AnsweredQuestion>();
...
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//iterate over datasnapshot to get/store each AnsweredQuestion object
if(datSnapshot.exists()){
for(DataSnapshot snapshot : dataSnapshot.getChildren()){
AnsweredQuestion answer = snapshot.getValue(AnsweredQuestion.class);
mAllAnswers.add(answer);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
//handle error
}
});
There are multiple ways to retrieve the answers for each user, using .addListenerForSingleValueEvent() is just one way. You can also use a FirebaseListAdapter or FirebaseRecyclerAdapter if you wanted to display the answers in a ListView or RecyclerView.
Related
Basically what I am trying to do is I have a database with the name users having an attribute username. I have some usernames in one list and I want to show details of these users only whose username is present in the list. How can I write a query to fetch details of those users only whose username is found in this list? And note that there is no lexicographical ordering so i can't use startAt() and endAt() functions as well.
code snippet:
=> myList contains usernames. This code doesn't yield accurate results.
Any help would be really appreciated! Thank you!
FirebaseRecyclerOptions<MainModel> options =
new FirebaseRecyclerOptions.Builder<MainModel>()
.setQuery(FirebaseDatabase.getInstance().getReference().child("users").orderByChild("username")
.startAt(myList.get(0)).endAt(myList.get(myList.size()-1)),MainModel.class).build();
As already mentioned in the comment, the Firebase-UI library doesn't help in your case, because it doesn't allow you to pass multiple queries to the FirebaseRecyclerOptions object. So you need to perform a separate query and use the combined result.
When you are calling .get() on a Firebase Realtime Database query object, you are getting back a Task object. So the key to solving this problem is to use whenAllSuccess(Collection> tasks). In your case, it should look like this:
DatabaseReference db = FirebaseDatabase.getInstance().getReference();
DatabaseReference usersRef = db.child("users");
Query query = usersRef.orderByChild("username");
List<Task<DataSnapshot>> tasks = new ArrayList<>();
for (String username : myList) {
tasks.add(query.equalTo(username).get());
}
Tasks.whenAllSuccess(tasks).addOnSuccessListener(new OnSuccessListener<List<Object>>() {
#Override
public void onSuccess(List<Object> list) {
//Do what you need to do with your list.
for (Object object : list) {
MainModel mm = ((DataSnapshot) object).getValue(MainModel.class);
if(mm != null) {
Log.d("TAG", mm.getUsername());
}
}
}
});
Assuming that you have in your MainModel class a getter called getUsername(), the result in your logcat will be all the usernames of all returned children.
I'm having some trouble deleting nodes in Firebase
This is how I upload my data
BigBoy add = new BigBoy(addCate);
myRef.push().setValue(add);
This is how i'm trying to delete my data
databaseReference = FirebaseDatabase.getInstance().getReference().child("message");
myRef = database.getReference("message");
String sfasf = Utils.object.getSfasf();
DatabaseReference remove = FirebaseDatabase.getInstance().getReference("message").child(sfasf);
remove.removeValue();
But the problem is that the node is not being deleted.
Make your firebase call like this -
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("message");
reference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot dataSnapshots : dataSnapshot.getChildren()){
if (dataSnapshots.child("sfasf").exists()) {
dataSnapshots.child("sfasf").removeValue();
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
1) You have a reference object but you dont use it. You have created 2 variable references and you dont use them.
2) Your code is wrong in order to remove the node you must specify the key
myRef = database.getReference("message");
myRef.child(key).remove();
---edit---
try this
myRef.child(key).removeValue();
---edit---
From the official documentation:
The simplest way to delete data is to call removeValue() on a reference to the location of that data. You can also delete by specifying null as the value for another write operation such as setValue() or updateChildren(). You can use this technique with updateChildren() to delete multiple children in a single API call.
The problem was that I wasn't referencing the pushID when I was referencing the specific data node. That was solved by saving the key as well when I upload the data.
Actually i want to get online users only not the whole list of users.
This is my database structure:
Users
- Uid
- online : true
i want to get list of users which are online without needing to get each one of the user and then sorting it by checking the datasnapshot.
Assuming that Users node is a direct child of the Firebase root, i recomand you using the following code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
Query query = rootRef
.child("Users")
.child("Uid")
.orderByChild("online")
.equalTo(true);
query.addListenerForSingleValueEvent(/* ... */);
Edit1: If you don't have the uid of each user, please use the following code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference usersRef = rootRef.child("Users");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String uid = ds.getKey();
Query query = usersRef.child(uid).orderByChild("online").equalTo(true);
query.addListenerForSingleValueEvent(/* ... */);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
usersRef.addListenerForSingleValueEvent(eventListener);
Edit2: As you can see in the offical documentation, addListenerForSingleValueEvent adds a listener for a single change in the data at this location. This listener will be triggered once with the value of the data at the location.
When you write data and if you'd like to know when your data has been committed, you can add a OnCompleteListener which is called when the Task completes. Both setValue() and updateChildren() methods take an optional completion listener that is called when the write has been committed to the database. This is an example:
yourRef.setValue("I'm writing data", new Firebase.CompletionListener() {
#Override
public void onComplete(FirebaseError firebaseError, Firebase firebase) {
if (firebaseError != null) {
System.out.println("Data could not be saved. " + firebaseError.getMessage());
} else {
System.out.println("Data saved successfully.");
}
}
});
Regarding synchronizing, there is a common way to detect when Firebase is done synchronizing the initial data on a given location. This approach makes use of one of the Firebase event guarantees:
Value events are always triggered last and are guaranteed to contain updates from any other events which occurred before that snapshot was taken.
So if you have both a ValueEventListener and a ChildEventListener on a given location, the ValueEventListener.onDataChange() is guaranteed to be called after all the onChildAdded() calls have happened.
But one thing to keep in mind: Firebase doesn't just load data. It continuously synchronizes data from the server to all connected clients. As such, there is not really any moment where the data is completely retrieved. That's why you need to remove the listener as explained below.
Furthermore, note that you can remove the listener whenever you want. The best practice is to remove it accordingly to the life-cycle of your activity.
If you have added the listener in onStart you have to remove it in onStop.
If you have added the listener in onResume you have to remove it in onPause.
If you have added the listener in onCreate you have to remove it in onDestroy.
But remember onDestroy is not always called.
databaseReference.removeEventListener(valueEventListener);
You can filter your items by specifying the child and value like this:
ref.orderByChild("online").equalTo(true);
More info here: https://firebase.google.com/docs/database/android/lists-of-data
Use this code
ref.child('Uid')
.orderByChild('online')
.equalTo(true);
or use
FirebaseDatabase.getReference("Users").child("Uid").orderByChild("online").equalTo(true);
I have several strings stored under specific reference: mReference.child(rID).child(userID2) which I want to retrieve using childEventListener as I am doing some task also when these string gets removed and that is only possible with onChildRemoved of ChildEventListener.
Here's what I have tried:
mReference.child(rID).child(userID2).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Log.d("dataHEre", dataSnapshot.getValue().toString());
}
}
The problem is that I'm unable to retrieve data using keys here as dataHEre is logging out:
D/dataHEre: 28.8419556
D/dataHEre: 78.779063
D/dataHEre: 3
D/dataHEre: Railway Colony
D/dataHEre: Sleep
D/dataHEre: 12:36 AM
D/dataHEre: Superman
which are values?
So, I want to know how can I retrieve data here using keys and using ChildEventListener and then assign the data retrieved to various strings?
I think that you are doing your query in the wrong way. onChildAdded method is retrieving you each child of a specific value (userID2 I suppose). If that is what you want, then just use a onValueEventListener() to retrieve the whole dataSnapshot of your userId2 node each time that it changes.
If you want to retrieve the data just once, you should use onSingleValueEventListener(). And OnChildEvent() is used to retrieve lists of data where you want to track each of the child individually. For example if you attach an OnChildEventListener to mReference.child(rID) you will get a OnChildAdded for each userId, what is pretty usefull like for example fill a RecyclerView or a ListView being able to update each item individually together with your Firebase Data.
If i'm not wrong what you want is just get updates of your userId2 reference, in that case attach a OnValueEventListener to that reference and you will get a call each time a value is modified, deleted, or added.
firebaseDatabaseRef.addValueEventListener(new ValueEventListener() {
#Override public void onDataChange(DataSnapshot dataSnapshot) {
customPOJO customPOJO = dataSnapshot.getValue(YourCustomPOJO.class);
customPOJO.getName();
customPOJO.getEmail();
customPOJO.getfavoriteFood();
//and so on....
}
#Override public void onCancelled(DatabaseError databaseError) {
}
});
I have the following data structure on firebase for the user MF0qeRA4p7djfjgXxqwFOck3m6p02. I want to get the value of item3 to populate a single field into the User interface on an Android App. I have been looking through samples on Stackoverflow, but all I have found are outdated and do not work with the current version of firebase. I'm new to firebase completely and this is my first app on android. I've got the oncreate user method to populate the users email address and add the 4 item fields, but retrieving the data I'm completely lost and I am not sure where to even begin.
-Users
---MF0qeRA4p7djfjgXxqwFOck3m6p02
------item1:"1"
------item2:"2"
------item3:"3"
------item4:"4"
According to what I can identify is, you are facing problem retrieving data from this reference. Here is the code:
final DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("Users");
databaseReference.child("MF0qeRA4p7djfjgXxqwFOck3m6p02").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String, Object> map=(Map<String, Object>)dataSnapshot.getValue();
String item3=(String)map.get("item3");
display(item3);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Hope this helps.
You can create a custom model and inside you can insert elements. Something like this:
public class Item {
private List<Object> ojects;
}
There you can save instance of Item on database. In this case you have more controll. Other case is to use push() method, that will generate a new encoded key, something like this:
mDatabase.child("items").push().put(new Object());