I'm new to Firestore but I am trying to get all the details from a collection inside a document inside a collection as shown below, store it in a list and display it in a LazyColumn
inside a Scaffold
. However, when I tried using an if-else statement, it shows that the list is empty:
(https://i.sstatic.net/3KWjs2Il.png) (https://i.sstatic.net/fzkVuje6.png)
This is the code that I am working with getting the data
class RestaurantViewModel: ViewModel() {
private val firestore = FirebaseFirestore.getInstance()
val restaurantList: MutableState<List<restaurantInfo>> = mutableStateOf(emptyList())
init {
fetchItems()
}
private fun fetchItems(){
val tempList = mutableListOf<restaurantInfo>()
firestore.collection("restaurants")
.get()
.addOnSuccessListener {
querySnapshot->
val documents = querySnapshot.documents
documents.forEach {
document->
val documentRef = document.reference.collection("details")
documentRef
.get()
.addOnSuccessListener {
subDocuments->
subDocuments.forEach {
subDocument->
val data = subDocument.data
val restaurantItem = restaurantInfo(
distance = data["distance"] as String?: "",
location = data["location"] as String?: "",
name = data["name"] as String?: "",
picture = data["picture"] as String?: "",
rating = data["rating"] as String?: "",
)
tempList.add(restaurantItem)
}
}
.addOnFailureListener{
exception->
Log.e("Firestore", "Error getting documents: ", exception)
}
}
restaurantList.value = tempList.toList()
}
.addOnFailureListener {
exception->
Log.e("Firestore", "Error getting restaurants", exception)
}
}
}`
Here is the data class:
data class restaurantInfo(
var distance: String? = "",
var location: String? = "",
var name: String? = "",
var picture: String? = "",
var rating: String? = ""
)
Here is where I am displaying it:
@Composable
fun Restaurants(
navController: NavController,
accountViewModel: AccountViewModel,
restaurantList: List<restaurantInfo>
){
val userInfo by accountViewModel.itemList
Scaffold(
topBar = {
TopBar(
title = "Account",
isRestaurantsScreen = true,
onBackNavClicked = {navController.navigateUp()},
userInfo = userInfo.firstOrNull()
) },
bottomBar = { BottomBar(navController) }
) {
paddingValues->
if(restaurantList.isEmpty()){
Text("No restaurants found", modifier=Modifier.padding(paddingValues))
}else{
LazyColumn(modifier = Modifier.padding(paddingValues)){
items(restaurantList){
item->
Card(
modifier = Modifier
.fillMaxWidth()
.padding(10.dp),
colors = CardDefaults.cardColors(
containerColor = Color.White
),
elevation = CardDefaults.cardElevation(
defaultElevation = 5.dp
),
shape = RoundedCornerShape(10.dp)
) {
Row{
Image(
painter = rememberImagePainter(item.picture),
contentDescription = null,
modifier = Modifier
.size(100.dp)
.padding(end = 8.dp)
)
Column(
modifier = Modifier.padding(8.dp)
) {
Text(
text = item.name.toString(),
fontSize = 15.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(bottom = 2.dp),
color = Color.Black
)
Text(
text = item.distance.toString(),
fontSize = 13.sp,
fontWeight = FontWeight.Light
)
Row {
Icon(
imageVector = Icons.Default.LocationOn,
contentDescription = null,
tint = Color.Green,
modifier = Modifier.padding(end = 5.dp)
)
Text(
text = item.location.toString(),
fontSize = 11.sp,
fontWeight = FontWeight.ExtraLight
)
}
Row{
Text(
text = item.rating.toString(),
fontSize = 11.sp,
fontWeight = FontWeight.Bold,
color = Color.Green,
modifier = Modifier.padding(end = 5.dp)
)
Icon(
imageVector = Icons.Default.Star,
contentDescription = null
)
}
}
}
}
}
}
}
}
}
And here is the result result Any help is appreciated and thank you in advance!
The issue with your code maybe the restaurantList being updated outside the nested Firestore
addOnSuccessListener
callbacks, which leads to the list being empty when it's accessed by your Composable
function.
Firestore's data retrieval is asynchronous
, so when the restaurantList.value
is set, the tempList might not have been fully populated yet. To fix this, you should move the update of the restaurantList
inside the nested callback after you've finished adding items to tempList
.
Here's an updated version of your fetchItems method:
private fun fetchItems() {
firestore.collection("restaurants")
.get()
.addOnSuccessListener { querySnapshot ->
val tempList = mutableListOf<restaurantInfo>()
val documents = querySnapshot.documents
val totalDocuments = documents.size
var completedDocuments = 0
documents.forEach { document ->
val documentRef = document.reference.collection("details")
documentRef
.get()
.addOnSuccessListener { subDocuments ->
subDocuments.forEach { subDocument ->
val data = subDocument.data
val restaurantItem = restaurantInfo(
distance = data["distance"] as String? ?: "",
location = data["location"] as String? ?: "",
name = data["name"] as String? ?: "",
picture = data["picture"] as String? ?: "",
rating = data["rating"] as String? ?: ""
)
tempList.add(restaurantItem)
}
completedDocuments++
if (completedDocuments == totalDocuments) {
restaurantList.value = tempList.toList()
}
}
.addOnFailureListener { exception ->
Log.e("Firestore", "Error getting documents: ", exception)
}
}
}
.addOnFailureListener { exception ->
Log.e("Firestore", "Error getting restaurants", exception)
}
}