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!
2
Answers
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 yourComposable
function.Firestore’s data retrieval is
asynchronous
, so when therestaurantList.value
is set, the tempList might not have been fully populated yet. To fix this, you should move the update of therestaurantList
inside the nested callback after you’ve finished adding items totempList
.Here’s an updated version of your fetchItems method:
If you want to get all the
details
of all therestaurants
, there is no need to loop through the data in Firestore twice, you can simply use a collection group query by calling collectionGroup(collectionId: String) and pass the ID of the sub-collection like this: