Firestore Query chaining using AND - android

How to chain the query parameters for Firestore. I want to dynamically add query parameters (along with some common ones). But it does not seem to be working. Is this a firestore limitation?
Chaining in the same line works:
db.collection("MY_COLLECTION")
.whereEqualTo("user.firebaseUserId" , FirebaseAuth.getInstance().getUid())
.whereEqualTo("formId",formId)
.whereEqualTo("user.active","true")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
FirestoreResponse response = new FirestoreResponse();
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
//getting results here - works!
} else {
}
}
});
But trying to add the conditions on the query object reference returns results only based on the 1st condition specified:
Query firebaseQuery = collectionReference. whereEqualTo("user.firebaseUserId" , "myuserId"); //only this condition is applied
firebaseQuery.whereEqualTo("user.active","true");
if(someCondition){
firebaseQuery.whereEqualTo("user.smart","true");
}
firebaseQuery.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
FirestoreResponse response = new FirestoreResponse();
if (task.isSuccessful()) {
//returns results only based on the 1st condition !!
} else {
}
}
});
This is strange since the .whereEqualTo returns a Query object.
I have also tried using CollectionReference.get() - along with adding query before to CollectionReference.

I figured out the issue - I was reusing the same query object "firebaseQuery " and calling whereEqualTo on the same object.
The whereEqualTo needs to be called on the query object from previous step instead of using the first query ref.
Query firebaseQuery1 = db.collection("MY_COLLECTION")
.whereEqualTo("user.firebaseUserId" , "someUserId");
Query firebaseQuery2 = firebaseQuery1.whereEqualTo("formId",formId);
Query firebaseQuery3 = firebaseQuery2.whereEqualTo("user.active","true");
firebaseQuery3.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
FirestoreResponse response = new FirestoreResponse();
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
works now !!
//}
} else {
}
}
});

Related

FirebaseFirestore add() method being executed before validation (get() documents) [duplicate]

This question already has answers here:
How to return a DocumentSnapShot as a result of a method?
(2 answers)
Closed 2 years ago.
I'm building an APP and using Firestore to create a collections of Users. Before adding the new user to the collection i need to check within the collection if the email is already in use and for this i've built two methods: one for reading the collection looking for an user with that email and the other one to adding the new user IF everything is ok. But no matter what I do, the add method always executes first leading to the validation being useless. I guess it's has something to do with the methods priority withing Firebase but i really couldn't pull out with a solution
Here's the two methods
The first one it's validation and the second one it's the add
private boolean createFirestoreUser(final String identificador) {
final boolean[] isValid = {true};
FirebaseFirestore.getInstance().collection("Usuarios")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
for (QueryDocumentSnapshot document : task.getResult()) {
if(identificador.equals(document.getString("identificador")))
isValid[0] = false;
}
}
});
return isValid[0];
}
private void createUser(Usuario novoUsuario) {
FirebaseFirestore.getInstance().collection("Usuarios")
.add(novoUsuario)
.addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
#Override
public void onSuccess(final DocumentReference documentReference) {
documentReference
.update("id", documentReference.getId())
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
loginSessionManager.createLoginSession(documentReference.getId());
loginSessionManager.checkLogin(this.getClass());
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
}
});
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
snackbar.showMensagemLonga(v,e.getMessage());
}
});
}
The second one is ALWAYS being called first no matter the order i use on the button listener. I've debbuged and it really enters in the isValid[0] = false after the user is added
Where are you calling the methods?
You could just call the createUser inside of the .addOnSuccessListener this way it will not be called until the valdiation is returned.
Something like:
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
for (QueryDocumentSnapshot document : task.getResult()) {
if(identificador.equals(document.getString("identificador")))
isValid[0] = false;
else
createUser(novoUsuario)
}
}
The reason why I'm asking where you are calling the methods is because your variable might be by default true which would trigger the second function before the async listener is returned therefore calling the second method before the validation is made.
So the alternative would be to call the register method inside the same mehrod where you are validating or if what I'm assuming that you have a boolean declared first to see if you call the create method, just have it false as default and make sure to be calling it after the async .OnCompleteLister is finished.

Random document that doesnt exist in firestore gets selected on android and deleted

I am trying to delete a document from Firestore. I am trying to do this based on the task ID that was randomly generated by Firestone. when a particular task is selected on android, I want to be able to delete that task. However, when I tried debugging the code, it shows a random ID that doesn't exist on the database and tries to delete that, sending me a success message in the console. I am not sure where I am going wrong. Please advice.
public void deleteTasks(View v) {
userId = mFirebaseAuth.getCurrentUser().getUid();
String tskid= fStore.collection("usersData").document(userId).collection("tasks").document().getId();
DocumentReference taskref = fStore.collection("usersData").document(userId).collection("tasks").document(tskid);
taskref.delete().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
Log.d("tag", "Task Deleted Successfully");
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d("tag", "Task Deletion Unsuccessful");
}
});
}
the above delete method is called on the button using android:OnClick
The Task I'd like to delete is Circled
When you are using the following line of code:
String tskid= fStore.collection("usersData").document(userId)
.collection("tasks").document()
.getId();
You are generating a new random ID. Actully, you are reserving a key for a document that you'll be writing in the future. When using this line:
DocumentReference taskref = fStore.collection("usersData").document(userId)
.collection("tasks").document(tskid);
You are creating a reference to that location. However, when using this line:
taskref.delete().addOnCompleteListener(/* ... */);
You are trying to delete a document that does not exist and this is because you didn't create it in the first place. If you need to delete a specific document, you need to know the ID. So the following lines of code will do the trick:
public void deleteTasks(View v) {
userId = mFirebaseAuth.getCurrentUser().getUid();
String tskid = "CQ45RKh8Ohd6DXjSQ8RO";
DocumentReference taskref = fStore.collection("usersData").document(userId)
.collection("tasks").document(tskid);
taskref.delete().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
Log.d("tag", "Task Deleted Successfully");
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d("tag", "Task Deletion Unsuccessful");
}
});
}
In order to delete that document, I have used the exact same ID that exists in the database.

firestore onSuccess listener isn't working

I am trying to download some Quiz objects from my database.
The following function is called from onCreate of a certain activity.
private void downloadQuizzesFromCloud(){
String user_id = FirebaseAuth.getInstance().getCurrentUser().getUid();
final FirebaseFirestore db = FirebaseFirestore.getInstance();
String user_quizzes_path = "users/".concat(user_id).concat("/quizzes");
Query userQuizzes = db.collection(user_quizzes_path);
userQuizzes.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
quizzes.clear();
for (QueryDocumentSnapshot document : task.getResult()) {
Quiz quizDownloaded = getQuizFromCloud(document.getId());
quizzes.add(quizDownloaded);
}
Toast.makeText(QuizzesActivity.this,"downloaded to list ".concat(String.valueOf(quizzes.size()).concat(" quizzes")), Toast.LENGTH_SHORT).show();
//TODO put in recycle adapter
} else { }
}
});
}
(user_quizzes_path contains the correct path to a collection of Quiz objects stored on the cloud)
I debugged this functions and found out that after the command:
userQuizzes.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>()
The function finishes execution, that is the onComplete cases aren't checked and executed and all this code is just skipped.
I tried to find this on the documentation of firebase but didn't find anything.
Why is this happening and how can I fix this?
Would appreciate some help here, thanks!
The onComplete is called when the read operation has completed from the Firestore servers. If it's not getting called, I can see two possible reasons:
You're not connected to the server. Unless you've read the data before (and it's in the local database that the Firestore client maintains), this means the read never completes locally.
You're not thinking asynchronously. Note that data is read from the server asynchronously, and there may be some time between when you call get() and when onComplete fires. To test if this is the case, put a breakpoint on if (task.isSuccessful()) { and run the app in the debugger. The breakpoint will hit when the data is read from the server.
Use a callback interface. Just like this below.
private void downloadQuizzesFromCloud(Consumer listener) {
String user_id = FirebaseAuth.getInstance().getCurrentUser().getUid();
final FirebaseFirestore db = FirebaseFirestore.getInstance();
String user_quizzes_path = "users/".concat(user_id).concat("/quizzes");
Query userQuizzes = db.collection(user_quizzes_path);
userQuizzes.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
List<Quiz> quizzes = new ArrayList<>();
for (QueryDocumentSnapshot document : task.getResult()) {
Quiz quizDownloaded = getQuizFromCloud(document.getId());
quizzes.add(quizDownloaded);
}
listener.onGet(quizzes);
Toast.makeText(QuizzesActivity.this,"downloaded to list ".concat(String.valueOf(quizzes.size()).concat(" quizzes")), Toast.LENGTH_SHORT).show();
//TODO put in recycle adapter
} else { }
}
});
}
interface Consumer {
void onGet(List<Quiz> quizzes);
}

how to delete firebase position value using swipe controller

how to delete firebase values using position (swipe controller)
if i delete values using below method,its delete random values,,i want delete selected value only
swipeController = new SwipeController(new SwipeControllerActions() {
#Override
public void onRightClicked(int position) {
firebaseRecyclerAdapter1.notifyItemRemoved(position);
firebaseRecyclerAdapter1.notifyDataSetChanged();
mDataRef = FirebaseDatabase.getInstance().getReference().child("OrderItemsList").child(gg);
mDataRef.child(d).removeValue().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
FancyToast.makeText(getApplicationContext(), "Removed Item", FancyToast.LENGTH_LONG, FancyToast.ERROR, R.drawable.ic_clear_black_24dp).show();
firebaseRecyclerAdapter1.notifyDataSetChanged();
firebaseRecyclerAdapter1.startListening();
}
}
});
It looks like you're using an adapter from FirebaseUI. In that case, you can get the DatabaseReference for the node at position with:
mDataRef = firebaseRecyclerAdapter1.getRef(position);
And then you can delete the data at that reference with:
mDataRef.removeValue().addOnCompleteListener(new OnCompleteListener<Void>() {
...
You need to specifiy which item you're trying to delete. For example, in your case, it should be:
mDataRef = FirebaseDatabase.getInstance().getReference().child("OrderItemsList");
mDataRef.child("Egg Rice").removeValue().addOnCompleteListener.. // and the rest..
Here is how it should be without code: OrderItemsList -> Egg Rice child.

Check if a document exists

I would like to check if a document exists in my collection "users" because when I try this code, it seems not to enter in the OnCompleteListener when the document doesn't exist (when no documents have a correct value with the field "user_uid") :
FirebaseFirestore db = FirebaseFirestore.getInstance();
db.collection("users").whereEqualTo("user_uid", user.getUid())
.limit(1).get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
} else {
Log.w(TAG, "Error getting documents.", task.getException());
}
}
});
When I have a document with my condition whereEqualTo("user_uid", user.getUid()), it's working.
So, how can I check if there is a document where the field "user_uid" == user.getUid()?
I copied your code, and tried your implementation of OnCompleteListener with limit(1). It worked with me on both scenarios where there are results, and no results.
Firestore has a way to check if there is no results by checking if it isEmpty() or not, before performing any operations. Because performing any operation will cause IndexOutOfBoundsException most of the time with iterating on getDocuments().
for example:
if (task.isSuccessful()) {
boolean isEmpty = task.getResult().isEmpty();
}
I hope this will help you.

Categories

Resources