Delete multiple datas sharing a same child from Firebase - Java - java

I have the following Firebase database
lessons :
Id_lesson : "XXX1"
Name_lesson : "Geography"
Date_lesson : "25/09/2018"
Id_lesson : "XXX2"
Name_lesson : "Mathematics"
Date_lesson : "25/09/2018"
Id_lesson : "XXX1"
Name_lesson : "Physics"
Date_lesson : "26/09/2018"
Id_lesson : "XXX2"
Name_lesson : "Biology"
Date_lesson : "26/09/2018"
I need to delete all the lessons entries from a specific date (sharing the same Date_lesson child).
I tried this method :
private void Delete_CR_Lessons(Date date) {
final String date_to_delete_string = DateFormat.getDateInstance(DateFormat.SHORT).format(date);
Log.i("Tag", "date to delete : "+date_to_delete_string);
DatabaseReference drTest = FirebaseDatabase.getInstance().getReference();
drTest.child("lessons").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
for(DataSnapshot dataSnapshot:snapshot.getChildren()) {
Log.i("Tag", "iteration for dataSnap");
if(dataSnapshot.hasChild(date_to_delete_string)){
dataSnapshot.getRef().setValue(null);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w("TAG: ", databaseError.getMessage());
}
});
During execution of the method (with String date "25/09/2018" for example), the entries are not deleted from Firebase Database. I see the two logs I specified but I also see a log called
"I/chatty: uid=10298(com.example.myname.lessonsmanagment) identical 2 lines"
I suppose that the method doesn't work because it cannot detect both Lessons from date 25/09/2018 (Geography and Mathematics) on the same time.
Does anyone have an idea on how to make it work ?

first of all, you need to query/order the data with the date
you can simply do it using this sample.
mRef.child("lessons").orderByKey().equalTo(Date_lesson)
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot postsnapshot :dataSnapshot.getChildren()) {
String key = postsnapshot.getKey();
dataSnapshot.getRef().removeValue();
}
});
where mRefis you lessons branch ref

Related

unable to make table using itext7 in android after getting data from firebase realtime database [duplicate]

public List<String> getContactsFromFirebase(){
FirebaseDatabase.getInstance().getReference().child("Users")
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Users user = snapshot.getValue(Users.class);
assert user != null;
String contact_found = user.getPhone_number();
mContactsFromFirebase.add(contact_found);
Log.i("Test", mContactsFromFirebase.toString());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return mContactsFromFirebase;
}
I can't seem to find the error. In the code above, when I call the log, I get the values from mContactsFromFirebase, but the getContactsFromFirebase() method return an empty list. Could you help me please?
Data is loaded from Firebase asynchronously. Since it may take some time to get the data from the server, the main Android code continues and Firebase calls your onDataChange when the data is available.
This means that by the time you return mContactsFromFirebase it is still empty. The easiest way to see this is by placing a few log statements:
System.out.println("Before attaching listener");
FirebaseDatabase.getInstance().getReference().child("Users")
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
System.out.println("In onDataChange");
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
System.out.println("After attaching listener");
When you run this code, it will print:
Before attaching listener
After attaching listener
In onDataChange
That is probably not the order that you expected the output in. As you can see the line after the callback gets called before onDataChange. That explains why the list you return is empty, or (more correctly) it is empty when you return it and only gets filled later.
There are a few ways of dealing with this asynchronous loading.
The simplest to explain is to put all code that returns the list into the onDataChange method. That means that this code is only execute after the data has been loaded. In its simplest form:
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Users user = snapshot.getValue(Users.class);
assert user != null;
String contact_found = user.getPhone_number();
mContactsFromFirebase.add(contact_found);
System.out.println("Loaded "+mContactsFromFirebase.size()+" contacts");
}
}
But there are more approaches including using a custom callback (similar to Firebase's own ValueEventListener):
Java:
public interface UserListCallback {
void onCallback(List<Users> value);
}
Kotlin:
interface UserListCallback {
fun onCallback(value:List<Users>)
}
Now you can pass in an implementation of this interface to your getContactsFromFirebase method:
Java:
public void getContactsFromFirebase(final UserListCallback myCallback) {
databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Users user = snapshot.getValue(Users.class);
assert user != null;
String contact_found = user.getPhone_number();
mContactsFromFirebase.add(contact_found);
System.out.println("Loaded "+mContactsFromFirebase.size()+" contacts");
}
myCallback.onCallback(mContactsFromFirebase);
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
Kotlin:
fun getContactsFromFirebase(myCallback:UserListCallback) {
databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(object:ValueEventListener() {
fun onDataChange(dataSnapshot:DataSnapshot) {
for (snapshot in dataSnapshot.getChildren())
{
val user = snapshot.getValue(Users::class.java)
assert(user != null)
val contact_found = user.getPhone_number()
mContactsFromFirebase.add(contact_found)
System.out.println("Loaded " + mContactsFromFirebase.size() + " contacts")
}
myCallback.onCallback(mContactsFromFirebase)
}
fun onCancelled(databaseError:DatabaseError) {
throw databaseError.toException()
}
})
And then call it like this:
Java:
getContactsFromFirebase(new UserListCallback() {
#Override
public void onCallback(List<Users> users) {
System.out.println("Loaded "+users.size()+" contacts")
}
});
Kotlin:
getContactsFromFirebase(object:UserListCallback() {
fun onCallback(users:List<Users>) {
System.out.println("Loaded " + users.size() + " contacts")
}
})
It's not as simple as when data is loaded synchronously, but this has the advantage that it runs without blocking your main thread.
This topic has been discussed a lot before, so I recommend you check out some of these questions too:
this blog post from Doug
Setting Singleton property value in Firebase Listener (where I explained how in some cases you can get synchronous data loading, but usually can't)
return an object Android (the first time I used the log statements to explain what's going on)
Is it possible to synchronously load data from Firebase?
https://stackoverflow.com/a/38188683 (where Doug shows a cool-but-complex way of using the Task API with Firebase Database)
How to return DataSnapshot value as a result of a method? (from where I borrowed some of the callback syntax)

Delete FireBase Value Without Knowing The Key Name

So I am working on the memories Firebase app and there is a stage where the user can upload photos to his memory. Each photo has uniq name "ImgLink0","ImgLink1",etc..
The function I am working on is to delete a specific photo when I am pressing a long click, but I can't reach the image in Firebase.
I tried like below but I got stuck because I can't identify the image key:
mDatabase.child(userUID).child("Memories").child(memoryName).child("Images").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot imageSnapshot : dataSnapshot.getChildren()) {
String imagesKey = imageSnapshot.getKey();
String imagesValue = (String) imageSnapshot.getValue();
Log.e("Test","" + imagesKey + "" + imagesValue);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
And this is the data structure:
I tried using query too but with no success because I don't have the image key.
Thank you for any help :)
To delete a node from the database, you need to know the completely path to that node.
Assuming you do know the URL of the image to delete, but not the key (ImgLink1 or ImgLink2) that is stored under, you're going to have to use a query to look up that key.
Something like:
DatabaseReference ref = mDatabase.child(userUID).child("Memories").child(memoryName).child("Images");
Query query = ref.orderByValue().equalTo("URL of the image")
query..addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot imageSnapshot : dataSnapshot.getChildren()) {
imageSnapshot.getRef().removeValue();
}
}
...
Also see these related answer:
deleting specific post in database(by post node) but it deletes entire database_table
How can i remove all fields and values by using key value or a field key from firebase realtime database?
To remove the second URL for example, please use the following lines of code:
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference imageToDeleteRef = rootRef
.child(uid)
.child("Memories")
.child("TestMem")
.child("Images")
.child("ImgLink1");
imageToDeleteRef.removeValue().addOnCompleteListener(/* ... */);
So I have created a reference that points exactly to ImgLink1 node and then I called .removeValue() on reference in order to delete it. So there is no need to read the value in order to perform a delete operation.
If you want to read the URL, please use these lines:
imageToDeleteRef.addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
#Override
public void onComplete(#NonNull Task<DataSnapshot> task) {
if (task.isSuccessful()) {
String url1 = task.getResult().child("ImgLink1").getValue(String.class);
Log.d("TAG", url1);
} else {
Log.d("TAG", task.getException().getMessage()); //Don't ignore potential errors!
}
}
});
The result in the logcat will be:
https://firebasestorage.googleapis.com...

Update a local variable by Firebase ValueEventListner and use that in my app, and avoid getting null value in android studio JAVA [duplicate]

public List<String> getContactsFromFirebase(){
FirebaseDatabase.getInstance().getReference().child("Users")
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Users user = snapshot.getValue(Users.class);
assert user != null;
String contact_found = user.getPhone_number();
mContactsFromFirebase.add(contact_found);
Log.i("Test", mContactsFromFirebase.toString());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return mContactsFromFirebase;
}
I can't seem to find the error. In the code above, when I call the log, I get the values from mContactsFromFirebase, but the getContactsFromFirebase() method return an empty list. Could you help me please?
Data is loaded from Firebase asynchronously. Since it may take some time to get the data from the server, the main Android code continues and Firebase calls your onDataChange when the data is available.
This means that by the time you return mContactsFromFirebase it is still empty. The easiest way to see this is by placing a few log statements:
System.out.println("Before attaching listener");
FirebaseDatabase.getInstance().getReference().child("Users")
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
System.out.println("In onDataChange");
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
System.out.println("After attaching listener");
When you run this code, it will print:
Before attaching listener
After attaching listener
In onDataChange
That is probably not the order that you expected the output in. As you can see the line after the callback gets called before onDataChange. That explains why the list you return is empty, or (more correctly) it is empty when you return it and only gets filled later.
There are a few ways of dealing with this asynchronous loading.
The simplest to explain is to put all code that returns the list into the onDataChange method. That means that this code is only execute after the data has been loaded. In its simplest form:
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Users user = snapshot.getValue(Users.class);
assert user != null;
String contact_found = user.getPhone_number();
mContactsFromFirebase.add(contact_found);
System.out.println("Loaded "+mContactsFromFirebase.size()+" contacts");
}
}
But there are more approaches including using a custom callback (similar to Firebase's own ValueEventListener):
Java:
public interface UserListCallback {
void onCallback(List<Users> value);
}
Kotlin:
interface UserListCallback {
fun onCallback(value:List<Users>)
}
Now you can pass in an implementation of this interface to your getContactsFromFirebase method:
Java:
public void getContactsFromFirebase(final UserListCallback myCallback) {
databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Users user = snapshot.getValue(Users.class);
assert user != null;
String contact_found = user.getPhone_number();
mContactsFromFirebase.add(contact_found);
System.out.println("Loaded "+mContactsFromFirebase.size()+" contacts");
}
myCallback.onCallback(mContactsFromFirebase);
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
Kotlin:
fun getContactsFromFirebase(myCallback:UserListCallback) {
databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(object:ValueEventListener() {
fun onDataChange(dataSnapshot:DataSnapshot) {
for (snapshot in dataSnapshot.getChildren())
{
val user = snapshot.getValue(Users::class.java)
assert(user != null)
val contact_found = user.getPhone_number()
mContactsFromFirebase.add(contact_found)
System.out.println("Loaded " + mContactsFromFirebase.size() + " contacts")
}
myCallback.onCallback(mContactsFromFirebase)
}
fun onCancelled(databaseError:DatabaseError) {
throw databaseError.toException()
}
})
And then call it like this:
Java:
getContactsFromFirebase(new UserListCallback() {
#Override
public void onCallback(List<Users> users) {
System.out.println("Loaded "+users.size()+" contacts")
}
});
Kotlin:
getContactsFromFirebase(object:UserListCallback() {
fun onCallback(users:List<Users>) {
System.out.println("Loaded " + users.size() + " contacts")
}
})
It's not as simple as when data is loaded synchronously, but this has the advantage that it runs without blocking your main thread.
This topic has been discussed a lot before, so I recommend you check out some of these questions too:
this blog post from Doug
Setting Singleton property value in Firebase Listener (where I explained how in some cases you can get synchronous data loading, but usually can't)
return an object Android (the first time I used the log statements to explain what's going on)
Is it possible to synchronously load data from Firebase?
https://stackoverflow.com/a/38188683 (where Doug shows a cool-but-complex way of using the Task API with Firebase Database)
How to return DataSnapshot value as a result of a method? (from where I borrowed some of the callback syntax)

Why is a loop stops Firebase from getting data? [duplicate]

public List<String> getContactsFromFirebase(){
FirebaseDatabase.getInstance().getReference().child("Users")
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Users user = snapshot.getValue(Users.class);
assert user != null;
String contact_found = user.getPhone_number();
mContactsFromFirebase.add(contact_found);
Log.i("Test", mContactsFromFirebase.toString());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return mContactsFromFirebase;
}
I can't seem to find the error. In the code above, when I call the log, I get the values from mContactsFromFirebase, but the getContactsFromFirebase() method return an empty list. Could you help me please?
Data is loaded from Firebase asynchronously. Since it may take some time to get the data from the server, the main Android code continues and Firebase calls your onDataChange when the data is available.
This means that by the time you return mContactsFromFirebase it is still empty. The easiest way to see this is by placing a few log statements:
System.out.println("Before attaching listener");
FirebaseDatabase.getInstance().getReference().child("Users")
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
System.out.println("In onDataChange");
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
System.out.println("After attaching listener");
When you run this code, it will print:
Before attaching listener
After attaching listener
In onDataChange
That is probably not the order that you expected the output in. As you can see the line after the callback gets called before onDataChange. That explains why the list you return is empty, or (more correctly) it is empty when you return it and only gets filled later.
There are a few ways of dealing with this asynchronous loading.
The simplest to explain is to put all code that returns the list into the onDataChange method. That means that this code is only execute after the data has been loaded. In its simplest form:
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Users user = snapshot.getValue(Users.class);
assert user != null;
String contact_found = user.getPhone_number();
mContactsFromFirebase.add(contact_found);
System.out.println("Loaded "+mContactsFromFirebase.size()+" contacts");
}
}
But there are more approaches including using a custom callback (similar to Firebase's own ValueEventListener):
Java:
public interface UserListCallback {
void onCallback(List<Users> value);
}
Kotlin:
interface UserListCallback {
fun onCallback(value:List<Users>)
}
Now you can pass in an implementation of this interface to your getContactsFromFirebase method:
Java:
public void getContactsFromFirebase(final UserListCallback myCallback) {
databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Users user = snapshot.getValue(Users.class);
assert user != null;
String contact_found = user.getPhone_number();
mContactsFromFirebase.add(contact_found);
System.out.println("Loaded "+mContactsFromFirebase.size()+" contacts");
}
myCallback.onCallback(mContactsFromFirebase);
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
Kotlin:
fun getContactsFromFirebase(myCallback:UserListCallback) {
databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(object:ValueEventListener() {
fun onDataChange(dataSnapshot:DataSnapshot) {
for (snapshot in dataSnapshot.getChildren())
{
val user = snapshot.getValue(Users::class.java)
assert(user != null)
val contact_found = user.getPhone_number()
mContactsFromFirebase.add(contact_found)
System.out.println("Loaded " + mContactsFromFirebase.size() + " contacts")
}
myCallback.onCallback(mContactsFromFirebase)
}
fun onCancelled(databaseError:DatabaseError) {
throw databaseError.toException()
}
})
And then call it like this:
Java:
getContactsFromFirebase(new UserListCallback() {
#Override
public void onCallback(List<Users> users) {
System.out.println("Loaded "+users.size()+" contacts")
}
});
Kotlin:
getContactsFromFirebase(object:UserListCallback() {
fun onCallback(users:List<Users>) {
System.out.println("Loaded " + users.size() + " contacts")
}
})
It's not as simple as when data is loaded synchronously, but this has the advantage that it runs without blocking your main thread.
This topic has been discussed a lot before, so I recommend you check out some of these questions too:
this blog post from Doug
Setting Singleton property value in Firebase Listener (where I explained how in some cases you can get synchronous data loading, but usually can't)
return an object Android (the first time I used the log statements to explain what's going on)
Is it possible to synchronously load data from Firebase?
https://stackoverflow.com/a/38188683 (where Doug shows a cool-but-complex way of using the Task API with Firebase Database)
How to return DataSnapshot value as a result of a method? (from where I borrowed some of the callback syntax)

How to view results of 2 Firebase queries in the same ArrayAdaptor in Android Studio

I'm Setting a Call log application that retrieve the data of Calls from one Firebase database Child and the name of the equivalent Contact from another Child.
I can run the queries and they retrieve the data but don't know how to cast then to the same Adaptor.
I'm using Android Studio and Firebase realtime database with little experience in both. My best result is this:
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
Person personList = dataSnapshot.getValue(Person.class);
String nombre = dataSnapshot.child("mNumber").getValue().toString();
Query query = mFirebaseDatabase.getReference("Names")
.orderByChild(nombre);
query.addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
String artist = snapshot.getValue().toString();
Person personName = snapshot.getValue(Person.class);
mContactsAdapter.add(personName);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
mContactsAdapter.add(personList);
}
This is how Firebase Realtime Database looks like
{
"Missed" : {
"-LmPZ-AOWIPSfEr-XK1v" : {
"mCheck" : "Check Out",
"mDate" : "16-08-19",
"mNumber" : "6505551212",
"mTime" : "15:13"
},
"-LmQGRvIYzAqqfmn94xU" : {
"mCheck" : "Check Out",
"mDate" : "16-08-19",
"mNumber" : "6505551213",
"mTime" : "18:32"
}
},
"Names" : {
"6505551212" : {
"mName" : "Bruce Wills"
},
"6505551213" : {
"mName" : "Peter Pan"
}
}
}
for now, the result looks like this
I want the same card to have the name AND the rest of the data.
I can run the queries and they retrieve the data but don't know how to cast then to the same Adaptor
There is no way you can pass two different queries to the same adapter instance. The best solution I can think of right now is to create an array or an ArrayList of the combined results in your client side code and then simply pass it to an ArrayAdapter. It's not the best solution since you'll need to query your database twice, but it will solve your problem.

Categories

Resources