How to get data from a specific field in Firestore (Android) - android

I am looking to get value from specific field in firestore.
Below is my sample json from firestore
{
"details":{
"name":"rahul",
"country":"India",
"phone":"1234567890"
},
"course":{
"subject":"cs",
"duration":"6 months"
}
}
I want to get the data from the field "details". I tried this below method and it's not working
override fun getStudentDetails() = callbackFlow {
val snapshotListener =
db.collection("studentDetails")
.document(Constants.FirestoreCollections.STUDENT_DETAILS_ID)
.collection(Constants.FirestoreCollections.Organisation.STUDENT_DETAILS)
.addSnapshotListener { snapshot, e ->
val taskResponse = if (snapshot != null) {
val tasks = snapshot.toObjects(Details::class.java)
Response.Success(tasks)
} else {
Response.Failure(e)
}
trySend(taskResponse)
}
awaitClose {
snapshotListener.remove()
}
}
Is there any way to achieve this?

Your snapshot object is a DocumentSnapshot. If you want to get a specific field, you can call get("details.name") (or any other relevant path).

To get the value of a specific field in the JSON data you provided, you can use the dot notation to access the field. For example, to get the value of the "name" field, you can use the following code:
jsonData.details.name
This will return the value "rahul". Similarly, you can use the dot notation to access other fields in the JSON data, such as "country" or "duration".
For example, to get the value of the "duration" field, you can use the following code:
jsonData.course.duration
This will return the value "6 months".
You can also use square bracket notation to access the fields in the JSON data. For example, the following code will also return the value of the "name" field:
jsonData['details']['name']
Keep in mind that the field names in the JSON data are case-sensitive, so make sure to use the correct capitalization when accessing them.

Related

Is there any efficient way to search throughout a list of objects every field?

Let's say I have an object
data class Person(
val name: String,
val surname: String,
val street: String,
val postalCode: String,
val telephoneNumber: String,
)
And then I have a list of persons :
val personsList = listOf(
Person(name="John", surname="Hams", street="Gariolg", postalCode="929429", telephoneNumer="+2142422422",),
Person(name="Karl", surname="Hamsteel", street="Gariolg", postalCode="124215", telephoneNumer="+3526522",),
Person(name="Stepf", surname="Hiol", street="Bubmp", postalCode="5342", telephoneNumer="+7574535",),
Person(name="Germa", surname="Foo", street="Hutioa", postalCode="235236", telephoneNumer="+112355",)
)
So now if the user types for instance Hams it should return John and Karl, because both have the word "Hams" inside the object. What I mean is doesn't matter if the user types postalCode, name, or whatever I'd like to loop throughout the object to check if there's any coincidence.
How i would do it, is create a function inside the data class, say, for example, like this. This will check if any field inside your data class matches with the given string.
In my example i check if whole string matches, but you can change this however you want. You probably want it.contains(searchString) inside the any block.
fun checkIfStringMatches(searchString: String) : Boolean =
setOf(this.name, this.surname, this.strees, this.postalCode, this.telephone).any { it == string }
Then, you can use this function on your list of persons to filter if any object matches your string search.
personList.filter{it.checkIfStringMatches(mySearchString)} // this will return a list with all the objects that match your search criteria
The problem is that if you add more fields, you will have to change this function and add it to the listOf() block. But i don't know any way to do this automatically without reflection, which is not really recommended to use. If you still want to use it, here is a question on this topic. Kotlin: Iterate over components of object
Try this, it will work.
personsList.filter { it.surname.startsWith("Hams") }.map {
Log.d("filter_name", it.name)
}
Hey You can apply filter method on list and grab the expected output like below :
val filtered = personsList.filter { it.toString().contains("Hams", true) }

How to covert the $document.data details to useful format so that I could use it in listviews

I would like to convert $document.data details to useful format so that I could use it for further applications. This is data from firestore documents.
private val mFireStore = FirebaseFirestore.getInstance()
mFireStore.collection("Users").whereEqualTo("lastName","H").whereEqualTo("firstName", "Uc").get()
.addOnSuccessListener{ documents ->
for(document in documents){
Log.d("TAG","${document.id}=>${document.data}")
Toast.makeText(applicationContext, "${document.id} => ${document.data}",
Toast.LENGTH_LONG).show()
}
}
.addOnFailureListener{exception ->
Log.w("TAG","Error getting documents:",exception)
Toast.makeText(applicationContext, "Failed",
Toast.LENGTH_LONG).show()
}
This is my code. Now when I run the code get this in the logcat
OL0rD4UfgHSh2K8UoTMnX6Xea6P2=>{lastName=H, image=, firstName=Uc, B=L, gender=, organization=, profileCompleted=0, mobile=0, blood group=o+, id=OL0rD4UfgHSh2K8UoTMnX6Xea6P2, email=jojoy09#gmail.com}
Now I want to convert this result to a useful format so that I could use it later. I wpuld like to convert the data so that I could load it in listview.
In the following for-loop:
for(document in documents) { ... }
The "document" object is of type DocumentSnapshot. When you call getData() on such an object, the type of object that is returned is a Map<String, Object>.
In Kotlin, this object is represented by Map<String, Any>. In order to get the data, you can simply iterate over the Map and get the data accordingly, using the following lines of code:
val map = document.data
for ((key, value) in map) {
Log.d("TAG", "$key = $value")
}
Or even simpler, using:
map.forEach { (key, value) -> Log.d("TAG", "$key = $value") }
However, if you only need, the value of a particular property, for example, the value of the email address, you can simply get it by using DocumentSnapshot#getString(String field) method:
val email = document.getString("email")
Log.d("TAG", email)
The result in the logcat will be:
jojoy09#gmail.com
.................
As I see in your screenshot, almost all of the properties are of type String. However, you can find different flavors for each type of field, like getLong(String field), getDouble(String field), getDate(String field), getTimestamp(String field), and so on.
Furthermore, if you need to get the entire document, and you want to convert it into an object of a specific class, as also #mehulbisht mentioned in his answer, you should use DocumentSnapshot#toObject(Class valueType). So assuming that you have a data class that looks like this:
data class User(
var email: String? = null,
var firstName: String? = null,
var lastName: String? = null,
//Other necessary fields
)
To convert the "document" object into an object of the "User" class, please use the following line of code:
val user = document.toObject(User::class.java)
Log.d("TAG", user.email)
The result in the logcat will be the same as above.
If you want to display a list of "User" objects in a ListView, then please check my answer from the following post:
What miss, with connect Firestore and ListView for random results in sample?
It's really simple to convert the Java code into Kotlin.
The Model that you used to set this data will be used here. You can convert the documents to your Model class using the .toObjects() method on it. Just use:
val myObjs = documents.toObjects(Model::class.java)
EDIT
For displaying this as a Log in Logcat use:
Log.d("myObjs ","""
$myObjs
""".trimIndent())
Do tell if this doesn't work for you :)

Can't able to store input data in firestore kotlin android

Here is the code
val db = Firebase.firestore
val user = hashMapOf(
"name" = "{binding.edit_name.text.toString()}",
"email" = "{binding.edit_email.text.toString()}
)
binding.submitBtn.setOnClickListener{
db.collection("users").add(user)
.addOnSuccessListener {
Toast.makeText(context,"Data inserted",Toast.LENGTH_LONG).show()
}
.addOnFailureListener {
Toast.makeText(context,"Error",Toast.LENGTH_LONG).show()
}
}
In above code edit_name , edit_text is input taken by keyboard. I can't able to store the user in firestore. I think there is problem of converting bindig.edit_name.text.toString() it can't able to convert string.
If i use hash map without taking input from keyboard as below then I am able to insert data in firestore.
val user = hashMapOf(
"name" to "ABC",
"email" to "abc#gmail.com"
)
This hash map is able to add in firestore.
I think there is problem in binding and I am also can't able to toast bindg.edit_name.toString() as shown below
binding.submitBtn.setOnClickListener{
Toast.makeText(context,"${binding.edit_name.text.toString()},Toast.LENGTH_LONG).show()
}
Please help in this. I think all problem is that I can't able to convert binding data value as a string (by default it is Editable).
According to the official documentation your code seems fine from the point of view of inserting data.
The issue seems indeed to rely on "binding.variable_input.text.toString()".
While investigating the Android Data Binding Library I came across this post, which recommends instead of using toString(), use:
String.valueOf(), or if you want to use toString(), try
Integer.valueOf().toString()
Expressions cannot be used for assignments in HashMap, so probably worth changing hashMapOf( "name" to "{binding.name.text.toString()}", "email" to "{binding.email.text.toString()}")
Better assign val name = binding.name.text.toString() and then hashMapOf( "name" to name)
Even better to create a custom object and set the values.
data class UserInfo (val name: String? = "",val email: String? = "") { constructor(): this("","")}

Convert map to object

I create Map <String,List<Object>>
val groupListByUserName = sharedList.groupBy { it -> it.user.displayName }
this function groupBy list by userNAme. Next I create model
data class SharedList(val userName:String,val sharedList: List<MovieMyList>)
I want add data with map to list and I don't konw how. Do you have any idea how make this?
If I understood correctly, you want to convert the Map<String, List<MovieMyList>> into a List<SharedList>, is that it?
val groupListByUserName = sharedList.groupBy { it -> it.user.displayName }
val sharedLists = groupListByUserName.map { (user, movies) -> SharedList(user, movies) }
Note that here, the parentheses in the lambda are important: calling map on a Map will deal with the map's entries, each composed of a key and a value. Using the parentheses performs destructuring on the entry to directly access its key and value.

Kotlin: How can I reduce child arrays into a single array?

I have a pice of code in Swift that reduces a list of TVSchedule objects into an array of TVMatch pobjects. Each TVSchedule, has a property called events, that is a list of TVMatches.
The code in swift is the following:
var matches: [TVMatch] {
let slots = timeSlots.reduce(into: [TVMatch]()) { (result, schedule) in
result.append(contentsOf: schedule.events)
}
return slots
}
I'm trying to do the same reduce in Kotlin and the code I have is the following:
val matches: ArrayList<TVMatch>
get() {
val slots = timeSlots.fold(arrayListOf<TVMatch>()) { result, schedule ->
result.addAll(schedule.events)
}
return slots
}
However, the Kotlin code gives me a type error, and does not compile. What is the problem here?
addAll returns a boolean, but the return value of the fold-operation should be of same type as the given initial object (in this case ArrayList).
You can solve that one easily by just adding result after your addAll-statement, e.g.:
result.addAll(schedule.events)
result // this is now the actual return value of the fold-operation
Alternatively just use apply or similar instead:
result.apply {
addAll(schedule.events)
} // result is the return value then
Note that you can actually simplify altogether using flatMap to just (side-note: if you use this approach the matches are evaluated only once of course, but flatMap is the star here anyway ;-))):
val matches = timeSlots.flatMap { it.events } // this is a new list! (note, if you do several mappings in a row, you may want to use timeSlots.asSequence().flatMap { }.map { }.toList() / or .toMutableList() instead
Alternatively if you really require the matches to be of type ArrayList, use flatMapTo instead:
val matches = timeSlots.flatMapTo(ArrayList()) { it.events }
You can of course keep the get() if you must, or just move the getting of the matches to its own function, e.g.:
fun getMatches() = timeSlots.flatMapTo(ArrayList()) { it.events }
Am I crazy, or can't you just replace the code with
val matches: List<TVMatch>
get() = timeSlots.flatMap { schedule -> schedule.events }
?

Categories

Resources