Firestore multiple whereEqualTo on nested HashMap - android

considering that multiple whereArrayContains() not working, I have problems with multiple whereEqualTo() on nested HashMap.
I am making simple chat app with firebase and, in some point, I need to determine if chat document from firestore exists for two user ids. My current firestore setup for chat is:
chatId : {
lastMessageText: string
lastMessageTime: long
memberIds: {
userId1 : true
userId2 : true
}
}
My code is:
chatsCollection
.whereEqualTo("memberIds., + currentUser.getUsername() "true") // which is memberIds.userId1
.whereEqualTo("memberIds." + opponentUser.getUsername(), "true")
.get()
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
if (!task.getResult().isEmpty()) {
// some logic
}
} else {
Log.d(TAG, "Error getting documents: ", task.getException());
}
});
but always returns empty result. I checked could firestore and everything is there. What am I missing?
Thanks in advance.

Your code looks like it's maybe trying to compare a boolean in the database with a String. If you have a boolean type field in the database, you should also be using a boolean type value in the query (not a string with quotes around it). Always make sure types match.

Related

How to save large arrayList in the same order as it is to firebase database in kotlin?

I am trying to save a list of data to the Firebase Realtime Database in Kotlin. But when I try to save the order gets shuffled as below.
This is my code. Here the locationlist is the array that contains the list of locations that I want to save in the same order as it is. But when I try to save the after the first element, 10th element is showed. And the pattern continues like that.
ref.child(pk).child("location${count+1}").setValue(locationList).addOnCompleteListener {
Toast.makeText(requireContext() ,"success$pk", Toast.LENGTH_SHORT).show()
}
If you are looking for an ascending order in code, the following lines will keep the order that exist in the array. Assuming you have a property "name" within each object, please try the following code:
val rootRef = FirebaseDatabase.getInstance().reference
val locationRef = rootRef.child("location2")
locationRef.get().addOnCompleteListener { task ->
if (task.isSuccessful) {
for (ds in task.result.children) {
val name = ds.child("name").getValue(String::class.java)
Log.d(TAG, name!!)
}
} else {
Log.d(TAG, task.exception!!.message!!) //Don't ignore potential errors!
}
}
}
If you want to change the order in the Firebase Console, please note that this is not possible. Check for a workaround in my answer from the following post:
How to order the nodes in firebase console based on key

add/overwrite field of type array in Firestore

I want to add a field of type array inside a collection.
if the field doesn't exist create it. if it exists overwrite it with the new array value.
the field should be called macAddress and it's of type array of String
I have tried the following:
val macInput = setting_mac_text.text.toString()
val macArray = macInput.split(",")
val macList = Arrays.asList(macArray)
val data =
hashMapOf(Pair(FirebaseConstants.USER_MAC_ADDRESS, macArray))
//save it in firebase
db.collection(FirebaseConstants.ORGANIZATION)
.document(orgID + ".${FirebaseConstants.USER_MAC_ADDRESS}")
.set(FieldValue.arrayUnion(macList))
.addOnCompleteListener { task ->
if (task.isSuccessful) {
Log.d(TAG, "successfully inserted")
} else {
Log.d(TAG, " failed ${task.exception}")
}
}
also tried to insert the list itself and hash map like this
val data = hashMapOf(Pair(FirebaseConstants.USER_MAC_ADDRESS, macArray))
db.collection(FirebaseConstants.ORGANIZATION)
.document(orgID)
.set(data))
but it keeps giving me java.lang.IllegalArgumentException: Invalid data. Nested arrays are not supported
what am I doing wrong here?
You're doing three things wrong here:
FieldValue.arrayUnion() is only meant to be used as the value of a field to add elements to that field. The way you are using it now in the first sample, it's being taken as the entire contents of the document.
set() with one parameter is only intended to create or overwrite an entire document. It can't be used to update an existing document. You would have to pass in SetOptions to tell it to merge if you want an update. Or, you would simply use update() to modify an existing document.
Your code that deals with macArray and macList isn't working the way you expect. You are creating a list with one element, which is itself an array. The error message is telling you that you can't have nested arrays like this.
I suggest taking a step back and simplifying your code, removing all the moving parts that don't have to do with Firestore. Just hard code values in your Firestore update until the update works the way you want, then add in the code that works with actual values. Get one simple thing to work, then add to it. If you get an error, you will know that the code you just added was incorrect.
To overwrite an array, you would simply call the set method and have the merge option set to true:
try {
const query = await DatabaseService.queryBuilder({
collection: CollectionName,
});
return await query
.doc(insuranceId)
.set(
{ DOCUMENT_PROPERTY_HERE: ARRAY_HERE },
{ merge: true }
);
} catch (exception) {
return Promise.reject(exception);
}

Check if a field exists - search through Firestore database

I am doing a project for school - android app which registers users to realtime database after it checks if there's a corresponding card number and phone number in a different database in Firestore. At the moment it verifies only the first document, but it wouldn't find the fields if I search for them in other documents.
This is the method I use:
public void checkIfCardExists() {
Query query = cardInfo.whereEqualTo("CardNo", cardNumber)
.whereEqualTo("Phone", userPhone);
query.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
boolean documentExists;
if (task.isSuccessful()) {
Log.d("QueryResult", "Is query result empty: " + task.getResult().isEmpty());
documentExists = !task.getResult().isEmpty();
}else {
Log.e("QueryResult", "Error getting documents.", task.getException());
documentExists = false;
}
if(documentExists) {
Log.d("QueryResult", "The document exists");
Toast.makeText(com.example.transportticket.RegistrationLeap.this, "Card number found",
Toast.LENGTH_SHORT).show();
userLeap = new UserLeap(userEmail, userPass, userName, userSurname, cardNumber, userPhone);
registerUserLeap(userEmail, userPass);
startActivity(new Intent(RegistrationLeap.this, Empty.class));
}else{
Log.d("QueryResult", "The document doesn't exist or there was an error retrieving it");
Toast.makeText(com.example.transportticket.RegistrationLeap.this, "Card number not found",
Toast.LENGTH_SHORT).show();
startActivity(new Intent(RegistrationLeap.this, Empty.class));
}
}
});
}
And this is how my Firestore database looks like
Firestore database
I added a photo to clarify about finding the first document
If you are using the following line of code:
Query query = cardInfo.whereEqualTo("CardNo", cardNumber)
.whereEqualTo("Phone", userPhone);
It means that you are telling Firestore to return all documents where the CardNo property holds the value of cardNumber AND the Phone property holds the value of userPhone. So if in your collection only one document satisfies this constraint, a single document will be returned. The other documents won't exist in the results. What you are doing now, is called filtering. However, if you want to get all documents, then you should remove both whereEqualTo() calls or directly use cardInfo which is a CollectionReference object. In this way, you aren't filtering anything. A CollectionReference object is basically a Query without any filters.
So using the last solution you can get all documents and you can also create the filtering on the client. This is not a recommended approach because getting all documents, will be very costly. For instance, if you have in your collection 1000 documents, you'll pay 1000 read operations to have them. So it's up to you to decide which one is better for you.

Can't read data from Firestore

Here it is Firestore Database
I am trying to register user with phone number, My aim is user can only register with only one phone number means there is no repetition , SO while registring i am reading in firestore that if entered number is available in database than it shows error else it will register. But while reading the data firestore return nothing. Also it not showing any error toast.The same function is working fine in other app.
Here is the code
mFireStore = FirebaseFirestore.getInstance()
mFireStore.collection("USERS")
.whereEqualTo("Number", number.text.toString())
.get()
.addOnSuccessListener { documents ->
for (document in documents) {
if( document != null ){
Log.i("Null","Document Not null")
Toast.makeText(this,"Phone Number Already Exist",Toast.LENGTH_SHORT).show()
}else{
val OTP = Intent(this#MainActivity,OTPActivity::class.java)
OTP.putExtra("Name",NAME.text.toString())
OTP.putExtra("Number","+"+92+number.text.toString())
OTP.putExtra("Age",age.text.toString())
OTP.putExtra("District",district.text.toString())
startActivity(OTP)
}
}
}
.addOnFailureListener { exception ->
Toast.makeText(this,exception.toString(),Toast.LENGTH_SHORT).show()
}
Here are my security Rules
match /{document=**} {
allow read, write: if true;
}
According to your comment:
The value of number is the "Number" stored in database i,e 03162026593
So when you are using the follow call:
.whereEqualTo("Number", number.text.toString())
You are actually passing 03162026593 and not +9203162026593 as it is in your database. To solve this, you should use the following query instead:
mFireStore.collection("USERS")
.whereEqualTo("Number", "+92" + number)
.get()
.addOnSuccessListener(/* ... */);
If you want to query Firestore database, you need to create index first. Go through this link and it would serve your purpose, hopefully!
When querying .whereEqualTo("Number", number.text.toString()), shouldn't you also add +92 to the number, like .whereEqualTo("Number", "+"+92+number.text.toString())?

Android Firestore query get the id of the document that contains the value in the search

Firestore database image
Hello, I just tried to use Firestore. I had some problem when getting document id.
The question is, I want to get a document id (red box) which has value (blue box) in it.
I use the following query:
collection("mychannel").whereEqualTo("74wRU4xHrcV9oWAXEkKeRNp41c53")
But did not give results.
Thanks!
As in the official documentation:
Although Cloud Firestore can store arrays, it does not support querying array members or updating single array elements.
So there is no way in which you can use the following query:
collection("mychannel").whereEqualTo("74wRU4xHrcV9oWAXEkKeRNp41c53")
If you only want to get the entire userId array you need to iterate over a Map like this:
collection("mychannel").document("1fReXb8pgQvJzFdzpkSy").get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
Map<String, Object> map = document.getData();
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getKey().equals("userId")) {
Log.d("TAG", entry.getValue().toString());
}
}
}
}
}
});
But note, even if userId object is stored in the database as an array, entry.getValue() returns an ArrayList, not an array.
So the output will be:
[74wRU4xHrcV9oWAXEkKeRNp41c53]
A better approach will be if you consider this alternative database structure, where each user id is the key in a map and all values are true:
userId: {
"74wRU4xHrcV9oWAXEkKeRNp41c53": true,
"AdwF...": true,
"YsHs...": true
}
This question is answered here: Firestore: Query by item in array of document
In summary, don't use arrays to store data in Firestore as the query you are trying to do is not available yet (remember it is still in beta). You should use a Map instead.

Categories

Resources