Deleting a document from Firestore via Auto-generated document ID - java

I'm trying to create a Property Rental application on Android using Firebase Firestore. Right now, I'm trying to implement a method to delete a specific document (property) within my collection inside Firestore. I figure it is by referencing the auto-generated ID for that particular document, but I simply couldn't get around it.
This is how the delete feature should work:
User clicks on a property item from the RecyclerView
It displays a full profile of that property
User clicks the delete button from the top right corner and deletes the property from the Firestore database
Here is my code where I'm stucked at:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
// The delete button
case R.id.action_delete_btn:
// Do this when user clicks on delete button
Toast.makeText(PropertyProfile.this, "You tried to delete this property", Toast.LENGTH_LONG).show();
deleteItem(item.getOrder());
return super.onOptionsItemSelected(item);
default:
return false;
}
}
// Here's my problem
private void deleteItem(int index) {
firebaseFirestore.collection("Posts")
.document("[DOCUMENT ID RIGHT HERE!]")
.delete()
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(PropertyProfile.this, "You successfully deleted this property", Toast.LENGTH_LONG).show();
}
});
}

In order to use the document id that you are looking for, first you need to store it in a variable. When you are adding a document to the database and you are using a call to document() method without passing an argument, a unique id is generated. To get that id, you should use the following code:
String documentId = postsRef.document().getId();
postsRef.document(documentId).set(yourModelObject);
In which postsRef is the CollectionReference object of your Posts collection and yourModelObject is the object of your Post class. I also recommend you store that id, as a property of your Post document.
Once you have this id, you can use in your refence like this:
firebaseFirestore
.collection("Posts")
.document(documentId)
.delete().addOnSuccessListener(/* ... */);

Related

How do i create a key with FirebaseDatabase

How can I program a key in my FirebaseDatabase that is created by the userName. wText should then be the text: "" Value.
I try to create a key but when i run my app it removes all values in my database
The Code:
`
// getting text from our edittext fields.
String nameValue = userName.getText().toString();
String textValue = wText.getText().toString();
// below line is for checking whether the
// edittext fields are empty or not.
if (nameValue.isEmpty() && textValue.isEmpty()) {
// if the text fields are empty
// then show the below message.
Toast.makeText(AddTextActivity.this, "Please add some data.", Toast.LENGTH_SHORT).show();
return;
} else {
// else call the method to add
// data to our database.
addDatatoFirebase(nameValue, textValue);
finish();
}
}
});
}
private void addDatatoFirebase(String name, String wText) {
// below 3 lines of code is used to set
// data in our object class.
Messages.setuserName(name);
Messages.setText(wText);
// we are use add value event listener method
// which is called with database reference.
myRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
// inside the method of on Data change we are setting
// our object class to our database reference.
// data base reference will sends data to firebase.
myRef.setValue(text);
// after adding this data we are showing toast message.
Toast.makeText(AddTextActivity.this, "data added", Toast.LENGTH_SHORT).show();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
// if the data is not added or it is cancelled then
// we are displaying a failure toast message.
Toast.makeText(AddTextActivity.this, "Fail to add data" + error, Toast.LENGTH_SHORT).show();
}
}); `
It seems you might be using set() function to update data in firebase.
( in your case setValue(), I'm not sure if it is Firebase function or user defined function , Firebase uses set() method in almost in every SDK, not sure about Java SDK for Firebase )
Please note that set() will replace the existing value, or create a new key if there isn't any.
Use update() function instead of set()
Ways to Save Data
set - Write or replace data to a defined path, like messages/users/
update - Update some of the keys for a defined path without replacing all of the data
push - Add to a list of data in the database. Every time you push a new node onto a list, your database generates a unique key, like
messages/users//
transaction - Use transactions when working with complex data that could be corrupted by concurrent updates
refer the docs here

How can I perform OR query while searching in firebase?

Here are the various attributes of a person.
I want to implement a search where the results come if any of the fields: specializationField, hospitalName or fullName have the same letters.
For example if I search 'sh', this person should appear in the field, because of the similar hospital name.
This is the code I am using to search only for fullName:
FirebaseRecyclerOptions<DoctorHelperClass> options =
new FirebaseRecyclerOptions.Builder<DoctorHelperClass>()
.setQuery(FirebaseDatabase.getInstance().getReference().child("Doctor").orderByChild("fullName").startAt(s.toUpperCase()).endAt(s.toLowerCase()+"\uf8ff"), DoctorHelperClass.class)
.build();
adapter = new DoctorsAdapters(options, FindDoctorActivity.this);
adapter.startListening();
binding.rvListDoctors.setAdapter(adapter);
Please help me out
As #Puf said, you can't achieve it at Firebase Realtime Database but you can do it at client side which mean at the Android part.
First, you cannot use FirebaseUI which is you are currently using, instead you need to use https://firebase.google.com/docs/database/android/read-and-write#read_data
ValueEventListener postListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// You have to make for each loop
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
DoctorHelperClass doc = snapshot.getValue(DoctorHelperClass.class);
//List them in an array
docList.add(doc);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
}
};
mPostReference.addValueEventListener(postListener);
Once you have added all the list of doctors. You can compare them using the arrayList.
You can do something like this.
private void searchDoc(final String inputDoc){
boolean isFound = false;
for (DoctorHelperClass doc in docList){
if (doc.getFullName() == inputDoc && doc.getHospitalName() == inputDoc){
isFound = true;
//Do something if found
}
}
}
I hope you get the concept of it.
There is no support for OR conditions in Firebase Realtime Database. You will either have to perform multiple queries and merge the results client-side, or create a specialized field for performing this search.
But given your question, you may be looking for text search capabilities that are well beyond what Firebase Realtime Database handles. Instead of trying to shoehorn those requirements onto Firebase, I recommend using an additional (or even other) database for meeting your text search requirements.
Also see:
Use firebase realtime database create search function
How to search anywhere in string in Firebase Database - Android
Searching in Firebase without server side code
Firebase and indexing/search

Custom Object Retrieved from Firebase Always Has Null Attributes

I'm trying to retreive a custom User object from Firebase as follows:
getUserFromDB(loggedInUserEmail);
viewModel = new ViewModelProvider(this).get(UserViewModel.class);
viewModel.sendUser(loggedInUser);
//...
public void getUserFromDB(String userEmail) {
DocumentReference docRef = db.collection("users").document(userEmail);
docRef.get().addOnSuccessListener(documentSnapshot -> {
loggedInUser = documentSnapshot.toObject(User.class);
Log.d("User Login", documentSnapshot.getId() + " => " + documentSnapshot.getData());
Toast.makeText(MainActivity.this, "Login successful.", Toast.LENGTH_SHORT).show();
});
}
However, the user being retreived always has null attributes.
Here's a screenshot from when I was debugging.
Note: I made sure my User class has a public empty constructor and all the attributes have a getter method.
Loading the user from the database is an asynchronous operation. While the data is being loaded, the main code continues and your viewModel.sendUser(loggedInUser) executes before the data is loaded. Then the success callback is fired and sets loggedInUser, but by that time the view model has already been initialized with the wrong value.
The rule is always quite simple: any code that needs data from the database, needs to be inside the success listener (or be called from there). So something like:
public void getUserFromDB(String userEmail) {
DocumentReference docRef = db.collection("users").document(userEmail);
docRef.get().addOnSuccessListener(documentSnapshot -> {
loggedInUser = documentSnapshot.toObject(User.class);
// 👈 Initialize ViewModelProvider here
viewModel = new ViewModelProvider(this).get(UserViewModel.class);
viewModel.sendUser(loggedInUser);
});
}
Also see:
How to check a certain data already exists in firestore or not

I want to delete the array stored in Firestore

I received the user's email and designated it as the name of the document,
and stored the user information in the document in an array. I tried running my code, but only the Toast message is executed, not deleted.
I have listed the arrays as a list using RecyclerView. Deletion will be implemented through showPop() method.
This is my Firestore database enter image description here
I want to delete index-0
private void showPopup(View v,final int position) {
PopupMenu popup = new PopupMenu(activity, v);
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener(){
#Override
public boolean onMenuItemClick(MenuItem menuItem) {
switch (menuItem.getItemId()) {
.....
case R.id.delete: //delete
final FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
final FirebaseFirestore db = FirebaseFirestore.getInstance();
final Map<String, Object> updates = new HashMap<>();
updates.put(user.getEmail(),FieldValue.delete());
//db.collection("medicinday").document(mDataset.get(position).getId())
// .delete()
db.collection("medicinday").document(user.getEmail()).update("add_day", FieldValue.arrayRemove(user.getEmail()))
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(....
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
....
There is no way you can delete/update an element at a specific index in a Firestore array. For more info, please check my answer from the following post:
Is there any way to update a specific index from the array in Firestore
In your particular case, the add_day property is an array that holds objects. If you want to remove an item from that array, you need to pass the entire object value of the item. It will not work if you just pass an index or one of the nested values in that item.
For your type of data, you'll need to build a Map with the exact content of your first item and pass that object to the update() method, like in the following lines of code:
String email = FirebaseAuth.getInstance().getCurrentUser().getEmail();
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference medicinDayRef = rootRef.collection("medicinday");
DocumentReference emailRef = medicinDayRef.document(email);
HashMap<String, Object> doc = new HashMap<>();
doc.put("day", "monday");
doc.put("king" , "A");
doc.put("nam" , "ren");
doc.put("time1" , "AM 7:30");
doc.put("time2" , "PM 2:30");
doc.put("time3" , "PM 8:30");
emailRef.update("add_day", FieldValue.arrayRemove(doc));
Be aware that if you don't know the entire item's contents, it will not work.
Another option might be to read the document, modify the list on the client by removing the item at the position one, write it modified list back to the document, and in the end simply write it back to Firestore.
More info about this topic can be found here:
Android Firestore querying particular value in Array of Objects
And in the following article:
How to map an array of objects from Cloud Firestore to a List of objects?
It seems like your line to delete from your Firestore is commented out, unless that is intentional for now.
From the picture you have sent, I understand that add_day is your array and 0 is the element you would like to delete. You could do so by accessing your document's field add_day, then using arrayRemove() to specifically delete the element of your choice.
Roughly referring to the linked documentation, I believe you could achieve this by running the following.
DocumentReference doc = db.collection("medicinday").document("222#naver.com");
ApiFuture<WriteResult> remove = doc.update("add_day", FieldValue.arrayRemove("0"));
System.out.println("Update time : " + arrayRm.get());

Query Firestore data and add one field to all the documents that match the query

I am building an Android app to sell books. My users can post ads for their used books and sell them. I am planning to add a feature where my users can opt to go anonymous. There will be checkbox with name Make me anonymous. If users check that box, their phone number and name will not be visible to others. Only a generic name should be visible.
Now the problem is, I want to put an entry anonymous = true in every ad documents that the user uploaded.
I want to query the ads that the user put and add a field anonymous = true. I want to do something like below:
final CheckBox anonymousCB = findViewById(R.id.anonymousCB);
anonymousCB.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (anonymousCB.isChecked()){
WriteBatch batch = firestore.batch();
DocumentReference sfRef = firestore.collection("books").whereEqualTo(uid,uid);
batch.update(sfRef, "anonymous", "true");
}
}
});
But I cannot make a query and insert a field into all the documents that match the query. Is there any better way to do this?
Is there any better way to do this?
Yes, there is. To solve this, please use the following lines of code inside onCheckedChanged() method:
Query sfRef = firestore.collection("books").whereEqualTo(uid, uid);
sfRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
List<String> list = new ArrayList<>();
for (DocumentSnapshot document : task.getResult()) {
list.add(document.getId());
}
for (String id : list) {
firestore.collection("books").document(id).update("anonymous", true).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "anonymous field successfully updated!");
}
});
}
}
}
});
The result of this code would be to add the anonymous property to all your book objects and set it to true. Please note, I have used the boolean true and not the String true as you have used in your code. Is more convenient to be used in this way.
P.S. If you are using a model class for your books, please also see my answer from this post.

Categories