How to map an array of objects from Realtime Database to a List of objects?
A simple solution for mapping an array of objects from the Realtime Database into a list of custom objects

Before starting, if you are using Cloud Firestore and you’re looking for a similar solution, I have already written an article regarding the same topic:
Getting back to our subject, technically speaking, the Firebase Realtime Database doesn’t store arrays. It can store structures called associate arrays, which represent:
An abstract data type that stores a collection of (key, value) pairs.
So if you think of something like this:
{
"products": [
"Laptop",
"Tablet",
"Mobile Phone",
"LCD TV",
"Smartwatch"
]
}That’s definitely possible. You can add such a structure either from code or directly from the Firebase Console.
When we read the array in our application code with one of the Firebase SDKs, it always will be translated into an array. In Android, we can do it like this:
val db = Firebase.database.reference
db.child("products").get().addOnCompleteListener {
if (it.isSuccessful) {
val products = it.result.value as List<String>
Log.d(TAG, products.toString())
} else {
Log.d(TAG, it.exception?.message.toString())
}
}The result in the console will be:
[Laptop, Tablet, Mobile Phone, LCD TV, Smartwatch]If we need to read the content of the entire array, there is one thing that needs to be mentioned, the DataSnapshot#getValue() method returns an object of type Object. Since the products node in the Realtime Database is an array, the type of object that is returned can be cast to a List<String>. There is also another solution that can allow us to iterate through all the children of the node, which is by using the DataSnapshot#getChildren() method. In code, it looks like so:
db.child("products").get().addOnCompleteListener {
if (it.isSuccessful) {
val products = it.result.children.mapNotNull { doc ->
doc.getValue(String::class.java)
}
//Do what you need to do with your list.
Log.d(TAG, products.toString())
} else {
Log.d(TAG, it.exception?.message.toString())
}
}There is one more solution that is worth to be mentioned. When we’re using the DataSnapshot#getValue() method, we can also cast the object to Map<String, Any>.
How about reading an array of custom objects?
To be able to translate the array that exists in the database into a List<Product>, the corresponding JSON structure should look like this:
{
"products": [
{
"name": "Laptop",
"price": 899.99
},
{
"name": "Tablet",
"price": 1099.99
},
{
"name": "Mobile Phone",
"price": 599.99
},
{
"name": "LCD TV",
"price": 1399.99
},
{
"name": "Smartwatch",
"price": 699.99
}
]
}How can we map the products node into a List<Product>?
Obviously, we can create a Product class:
data class Product (
var name: String? = null,
var price: Double? = null
)And use the exact same solution as above:
db.child("products").get().addOnCompleteListener {
if (it.isSuccessful) {
val products = it.result.children.mapNotNull { doc ->
doc.getValue(Product::class.java)
}
//Do what you need to do with the product list.
} else {
Log.d(TAG, it.exception?.message.toString())
}
}And instead of reading the value as a String, we read it as a Product.
But is there any other (simpler) solution?
For sure there is. We can use an GenericTypeIndicator object. In code, it should look as simple as:
db.child("products").get().addOnCompleteListener {
if (it.isSuccessful) {
val gti = object : GenericTypeIndicator<List<Product>>() {}
val products = it.result.getValue(gti)
//Do what you need to do with the product list.
} else {
Log.d(TAG, it.exception?.message.toString())
}
}Now, there is more question that comes to my mind.
How to add a new object inside the products array?
Unfortunately, there is no atomic operation that can allow us to add an Product object directly to the array. This means we’ll need to:
- Read the content of the array into our Android application code.
- Append the
Productobject to the array. - Write the entire array back to the Realtime Database.
This is one of the reasons why the Firebase team recommends against using arrays. Instead, it’s better to use the DatabaseReference#push() method, which generates a unique key each time is called. For more on this topic, I recommend reading this blog post:
However, if we only need a small amount of data, then storing data in an array is an option that you can take into consideration.
Conclusion
That’s the simplest solution for mapping an array of objects into a list of custom objects. I hope you found this article useful and if you have any questions regarding this topic, feel free and leave a comment in the section below.
You can also see it on YouTube:






