I want to apply a join operation on 2 nodes in firebase database. How will I do this?
Following is the structure of my database :
I have two nodes : user node and books node
I want to traverse books node and For every book I need to find every user's name (available in user node) who like that book .
I need to make an array of such names and display it in recycler view.
Is there any function which will trigger when all the data will be fetched?
Here is my code:
DatabaseReference bookRef;
bookRef.addOnSingleValueEventListener(new ValueEventListener ){
#Override
public void OnDataChanged(DataSnapshot datasnapshot){
//I will get userReference fromdatasnapshot
DatabaseReference userReference ;
userReference.addOnSingleValueEventListener(new ValueEventListener ){
#Override
public void OnDataChanged(DataSnapshot datasnapshot){
//Add Username in arrayList
}
}
}
}
You can add a HashMap<> for storing the likes of user which like the book inside the book node then you will have no need to travrse through the user node you can get the value of like Hashmap and set as recycle view or what you want
Related
I am trying to query nodes from Firebase realtime database to my firebase recycler adapter where "userId" child value is found in a String ArrayList.
So I have a node called "Follows" where every users follows inside the app are stored. It looks like this. Then I have node called "Posts" where every post by any user is stored. Every indivitual post have multiple childs containing info about the post and one of them is child called "userId". Looking like this.
I have retrieved each follows user id like this:
final ArrayList<String> usersFollows = new ArrayList<>();
DatabaseReference usersFollowsRef = FirebaseDatabase.getInstance().getReference().
child("Follows").child(currentUserId);
usersFollowsRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot)
{
if(dataSnapshot.exists())
{
for(DataSnapshot snapshot : dataSnapshot.getChildren())
{
String followsKey = snapshot.getKey();
usersFollows.add(followsKey);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Now I would have to make a query which retrieves every post that has "userId" value found in this "usersFollows" ArrayList but I don't really know how to achieve my goal. For example I cant write Query query = postsReference.orderByChild("userId").equalTo(usersFollows); because you cant pass an array inside equalTo() statement.
Am I on the right path or is there a more convinient way of doing this?
Unfortunately, firebase doesn't allow multiple equalTo(). I suggest you to review your db in that way: Posts -> Date -> UserId -> PostId and adding a .read rules that check if the UserId in Follow list is true:
Posts: {
"$date" :{
"$userId": {
".read": "root.child(follows).child(auth.uid).child($userId).val() === true"
}
}
}
In this way you can obtain the post by date and automatically reduce the visibility scope.
EDIT:
You can maintain your actual schema adding this rule:
Posts: {
"$post":{
".read": "root.child(follows).child(auth.uid).child(data.child(userId)).val() === true"
}
}
Firebase contains some departments node and doctors node so I have a relationship between doctors and departments with key department id. Each doctor has department id so I want to show in my query 5 child from doctors for each department how can I use query firebase to get result 5 children for doctors for each department android.
how to do the query in android?
I tried to query the department first
and then in for each department id make a query to get some child of doctors
but I think it will make my app slowly
Firebase node structure:
From what I understand from your question, you want to get list of 5 doctors who have a certain department Id.
You can do so using orderByChild() and limitToLast() and simple singleValueEventListener(). The code may look something like this:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("Doctors");
ref.orderByChild("depid").equalTo(2).limitToFirst(5).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot child: dataSnapshot.getChildren()) {
String name = dataSnapshot.child("name");
// or do anything else
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
This code will get first 5 doctors' names in the variable name one by one who have depid as 2. You can edit it according to your future needs.
You can use different depid values to show different doctors from different departments in this.
DatabaseReference databaseReference=mDatabase;
String queryText="Hotel";
databaseReference.orderByChild("Coupon")
.startAt(queryText)
.endAt(queryText+"\uf8ff");
Here I attached the code which I used to get child names of "Coupon" when I entered the "Hotel" query under the Coupon.But I got blank.I supposed to get Hotel1,Hotel2 object.I'm new to firebase.So hope your support .Thanks in advance.
In the Web version, they use something called ElasticSearch, you could try to read more here: https://firebase.googleblog.com/2014/01/queries-part-2-advanced-searches-with.html
But for Android, I think there isn't any functionality to perform a search like that. What I would do is to query all the records then filter them myself:
DatabaseReference databaseReference = mDatabase;
mDatabase.addValueEventListener(new ValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot val : dataSnapshot.getChildren()){
//I am not sure what record are you specifically looking for
//This is if you are getting the Key which is the record ID for your Coupon Object
if(val.getKey().contains("Hotel")){
//Do what you want with the record
}
//This is if your are querying for the hotel child
if(val.child("hotel").getValue(String.class).contains("Hotel")){
//Do what you want with the record
}
}
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
}
Don't load your whole database to filter out needed data. It produces unnecessary traffic which has to be loaded, calculated and deleted. Instead, use:
DatabaseReference myRef = FirebaseDatabase.getDatabaseReference();
Query searchQuery = myRef.child("Coupon").orderByChild("hotel").equalTo("yourSearchString");
To make this code work, you also have to add indexOn on your corresponding attribute in the rules (of Firebase Database console).
I want to update the date on Firebase on a specific node.
DB Structure:
I am trying as
private void updateData() {
database = FirebaseDatabase.getInstance();
myref = database.getReference();
myref.child("myDb").child("awais#gmailcom").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
dataSnapshot.getRef().child("leftSpace").setValue(newValue);
dialog.dismiss();
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.d("User", databaseError.getMessage());
}
});
}
I want to update the leftSpace key with the value of newValue, newValue is the type of string here. But it is not updating the value in Firebase.
If I give here
dataSnapshot.getRef().child("leftSpace").setValue(765);
it updates well. But I want to update in the format of string on the Firebase.
I saved the data on Firebase of all string types. (My pattern class contains all of the type strings)
Why it is not updating the newvalue of type string here?
Edit 1 Suggested by #Rjz Satvara
You method is adding a new node under myDB as
It is not updating the already one.
In Firebase To update specific value you can use it...
ref.child("myDb").child("awais#gmailcom").child("leftSpace").setValue("YourDateHere");
or you can move into child using "/" as follow :
ref.child("myDb/awais#gmailcom/leftSpace").setValue("YourDateHere");
you can assign new value in same child,like
Firebase firebase = new Firebase("your database link/myDb");
firebase.child("awais#gmail.com").child("leftSpace").setValue("newValue");
According to Firebase Official Documentation you can update the specific node of parent node in this way
Using setValue() in this way overwrites data at the specified location, including any child nodes. However, you can still update a child without rewriting the entire object. If you want to allow users to update their profiles you could update the username as follows:
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference mDatabaseRef = database.getReference();
mDatabaseRef.child("TABLE_NAME").child("orderStatus").setValue(2);
Note! TABLE_NAME mean your parent node whose child node you want to update.
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.