This question already has answers here:
How to check if a document exist in firestore kotlin?
(2 answers)
Closed last month.
I Have the same key M6LMD0D7oyW1ueNKU2c6sXcZZFd2 I just want to check if this is present or not in Firestore. How can I do this?
To check if a particular user (document) exists in a collection in Firestore, you can simply use a get() call and attach a complete listener. In code, it will be as simple as:
val uid = Firebase.auth.currentUser?.uid
val uidRef = Firebase.firestore.collection("users").document(uid)
uidRef.get().addOnCompleteListener {
if (it.isSuccessful) {
val document = task.result
if (document.exists()) {
Log.d(TAG,"The user already exists.")
} else {
Log.d(TAG, "The user doesn't exist.")
}
} else {
task.exception?.message?.let {
Log.d(TAG, it) //Never ignore potential errors!
}
}
}
This can be done with a simple get() query. For a more complex retrieval of a document like listening to live updates and performing filter operations please refer to the Firebase documentation.
val docRef = db.collection("users").document(user.userId) // Access userId
docRef.get()
.addOnSuccessListener { document ->
if (document != null) {
Log.d(TAG, "DocumentSnapshot data: ${document.data}")
} else {
Log.d(TAG, "No such document")
}
}
.addOnFailureListener { exception ->
Log.d(TAG, "get failed with ", exception)
}
Related
This question already has answers here:
How to return a DocumentSnapShot as a result of a method?
(2 answers)
Using .addOnSuccessListener to return a value for a private method
(2 answers)
Closed 12 months ago.
I am new to Firestore / Document DB / NoSQL, so please be patient with me on this.
I have something like below where a document is created in the "Users" collection when user sign in for the first time
class FirestoreService{
private val db = Firebase.firestore
private var userExists:Int = 0
private var documentRef = ""
fun addUser(user: User) {
// check if the user exists
db.collection("Users")
.whereEqualTo("Email", user.email).get()
.addOnSuccessListener { documents ->
// async, so following variables will not be initialized when
// synchronous code is being called
for (document in documents) {
documentRef = document.id
userExists = if(docRef!=null) 1 else 0
}
}
.addOnFailureListener { e ->
Log.w(TAG, "Error adding User document", e)
}
if (userExists == 0){
val userHashMap = hashMapOf(
"name" to user.name,
"email" to user.email,
"notif" to false
)
db.collection("Users")
.add(userHashMap)
.addOnSuccessListener { documentReference ->
Log.d(TAG, "User document added!")
Log.d(TAG, "DocumentSnapshot added with ID: ${documentReference.id}")
}
.addOnFailureListener { e ->
Log.w(TAG, "Error adding User document", e)
}
}
}
fun updateUser(user:User){
db.collection("Users")
.document(documentRef)
.set({
"notif" to user.settings?.notifOn
})
.addOnSuccessListener { Log.d(TAG, "User DocumentSnapshot successfully updated!") }
.addOnFailureListener { e -> Log.w(TAG, "Error updating User document", e) }
}
}
Inside a fragment
// inside fragment method
val firestoreService = FirestoreService()
firestoreService.addUser(user);
// inside another fragment method
firestoreService.updateUser(user2)
As you can see I am setting variables inside addOnSuccessListener which is asynchronous so the synchronous if condition and updateUser calls do not work as expected (required values may not be assigned to the userExists, documentRef when synchrnous code being called). As I know these async behavior is handled using callbacks like mentioned in here. But I am not sure how to make it work in my case with addOnSuccessListener?
How do I retrieve all the fields of the current user logged?
I've watched many tutorials and questions, and some of them talk about the whole collection, others about similar topics, but found no info about this.
Thank you
UPDATE
Current Code:
fun getUserName_FireBase(){
if(userID==null){
println("The userID is null")
userID= getUserID()
println("The userId has been assigned and now is: " + userID.toString())
}
println("1")
val db = FirebaseFirestore.getInstance()
println("1a")
val usersRef = db.collection("users")
println("1b")
usersRef.document(userID.toString()).get().addOnCompleteListener { task ->
println("2")
if (task.isSuccessful) {
println("3")
val document = task.result
if(document!!.exists()){
println("4")
userName = document!!.getString("user").toString()
println("user is " + userName.toString())
}else {
println("5")
Log.d("Error", "This document does not exist")
}
}else {
println("6")
task.exception?.message?.let {
Log.d(TAG, it)
}
}
println("7")
}
println("8")
}
Console error
The error is given because later I need to acces to userName var that is supposed to be filled in that function
To be able to get user data, you have to create a reference that points to that document, perform a get() call and attach a listener, as seen in the following lines of code:
val db = FirebaseFirestore.getInstance()
val usersRef = db.collection("users")
usersRef.document("gA4z1AhkQpQ6J47sIMmCGIZRKDK2").get().addOnCompleteListener { task ->
if (task.isSuccessful) {
val document = task.result
if (document.exists()) {
val email = document.getString("email")
val pass = document.getString("pass")
val user = document.getString("user")
Log.d(TAG,"$email/$pass/$user")
} else {
Log.d(TAG, "The document doesn't exist.")
}
} else {
task.exception?.message?.let {
Log.d(TAG, it)
}
}
}
The result in the logcat will be:
barrooroor#gmail.com/paport/do3fe4232ef2
If "gA4z1AhkQpQ6J47sIMmCGIZRKDK2" is the ID of the user that comes from the authentication process, then instead of the hard coded ID, you can simply use:
val auth = FirebaseAuth.getInstance()
val uid = auth.currentUser?.uid
usersRef.document(uid).get().addOnCompleteListener {/* ... /*}
// 👆
Besides that, something more important, never store sensitive data as passwords in plain text. Malicious users might take advantage of that. Always use Firebase Authentication for that and secure the database using Firestore Security Rules.
I have a function where I validate a product as you can see in this snippet:
private fun validateProduct() : Boolean{
val newProductName = binding.etNewProductName.text.toString().trim()
val newProductPrice = binding.etNewProductPrice.text.toString().trim()
val newProductCategory = binding.spNewProductCategory.selectedItem.toString()
return when{
TextUtils.isEmpty(newProductName) -> {
showErrorSnackBar(binding.root, "Product name cannot be empty.", true)
false
}
TextUtils.isEmpty(newProductPrice) -> {
showErrorSnackBar(binding.root, "Price cannot be empty.", true)
false
}
//make sure the first element is not a valid category
newProductCategory == binding.spNewProductCategory.getItemAtPosition(0) -> {
showErrorSnackBar(binding.root, "Please select a valid category.", true)
false
}
//check if the new product's name already exists in the Firestore collection.
//if so, return false.
else -> {
true
}
}
}
Edit:
My logic in mind was to iterate over the documents. Check each document if document["name"].toString() == newProductName if so, return false and display an error snackbar.
Is there a way to check a Firestore document if its certain field is equivalent to some value?
Sure, there is. As you already said, yes, you have to iterate over the collection, but not for getting all documents and checking the new product name on the client. You have to do that in a query. Assuming that you have a collection called "products", to check if a specific product name already exists, please use the following lines of code:
val db = FirebaseFirestore.getInstance()
val productsRef = db.collection("products")
Query queryByProductName = productsRef.whereEqualTo("productName", newProductName)
queryByProductName.get().addOnCompleteListener { task ->
if (task.isSuccessful) {
if (!task.result.isEmpty) {
Log.d(TAG, "$newProductName already exists.")
} else {
Log.d(TAG, "$newProductName doesn't exist.")
}
} else {
Log.d(TAG, "Error getting documents: ", task.exception)
}
}
Hello, this is Kotlin Beginner.
While playing with Firestore, I suddenly had a question.
The value of a field can be easily retrieved, but
Is there a way to get the text of the field itself?
I would like to take the blue square in the following image literally.
Any help would be appreciated.
DocumentSnapshot#getData() method, returns an object of type Map<String!, Any!>. To get the keys of a document, simply iterate through the Map object, as explained in the following lines of code:
val uid = FirebaseAuth.getInstance().currentUser!!.uid
val rootRef = FirebaseFirestore.getInstance()
val uidRef = rootRef.collection("users").document(uid)
uidRef.get().addOnSuccessListener { document ->
if (document != null) {
document.data?.let { data ->
data.forEach { (key, _) ->
Log.d(TAG, key)
}
}
} else {
Log.d(TAG, "No such document")
}
}.addOnFailureListener { exception ->
Log.d(TAG, "get failed with ", exception)
}
To obtain the following result in the logcat:
email
id
nickname
password
phone
I have written a code to fetch data from Cloud Firestore and am trying to implement the network calls using coroutines. I have tried to follow the official guides as much as possible, but since the functions have been left incomplete in those docs, I have made adjustments according to my requirements, but those might be the problem itself.
Here's the function which fetches the data:
suspend fun fetchHubList(): MutableLiveData<ArrayList<HubModel>> = withContext(Dispatchers.IO) {
val hubList = ArrayList<HubModel>()
val liveHubData = MutableLiveData<ArrayList<HubModel>>()
hubsListCollection.get().addOnSuccessListener { collection ->
if (collection != null) {
Log.d(TAG, "Data fetch successful!")
for (document in collection) {
Log.d(TAG, "the document id is ")
hubList.add(document.toObject(HubModel::class.java))
}
} else {
Log.d(TAG, "No such document")
}
}.addOnFailureListener { exception ->
Log.d(TAG, "get failed with ", exception)
}
if (hubList.isEmpty()) {
Log.d(TAG, "Collection size 0")
} else {
Log.d(TAG, "Collection size not 0")
}
liveHubData.postValue(hubList)
return#withContext liveHubData
}
And here is the ViewModel class which is calling this method:
class HubListViewModel(application: Application): AndroidViewModel(application) {
// The data which will be observed
var hubList = MutableLiveData<ArrayList<HubModel>>()
private val hubListDao = HubListDao()
init {
viewModelScope.launch (Dispatchers.IO){
hubList = hubListDao.fetchHubList()
Log.d(TAG, "Array List fetched")
}
}
}
Using the tag messages I know that an empty list is being returned, which I know from another question of mine, is because the returned ArrayList is not in sync with the fetching operation, but I don't know why, since I've wrapped the whole function inside a with context block. Please tell me why the return and fetching is not being performed sequentially.
you should add this dependency "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.4.3". It allows you to use await() to replace callbacks.
suspend fun fetchHubList(): List<HubModel>? = try {
hubsListCollection.get().await().map { document ->
Log.d(TAG, "the document id is ${document.id}")
document.toObject(HubModel::class.java)
}.apply {
Log.d(TAG, "Data fetch successful!")
Log.d(TAG, "Collection size is $size")
}
} catch (e: Exception) {
Log.d(TAG, "get failed with ", e)
null
}
Dispatchers.IO is not necessary since firebase APIs are main-safe
class HubListViewModel(application: Application): AndroidViewModel(application) {
val hubList = MutableLiveData<List<HubModel>>()
private val hubListDao = HubListDao()
init {
viewModelScope.launch {
hubList.value = hubListDao.fetchHubList()
Log.d(TAG, "List fetched")
}
}
}