A solution can be found at the bottom. If you wish to understand the context read along!
Bloody beginner in Kotlin/Android here and trying his best.
I am trying to push a list of data objects into Firestore and managed to pull that off with the following function:
fun createData(collectionName:String){
//Create Data here
val docData: MutableMap<String, Any> = HashMap()
docData["data"] = Arrays.asList(
JournalEntry("Title 1", 0, 0),
JournalEntry("Title 2", 0, 1),
JournalEntry("Title 3", 0, 0)
)
db.collection(collectionName)
.add(docData)
.addOnSuccessListener { documentReference ->
Log.d(TAG, "DocumentSnapshot added with ID: ${documentReference.id}")
}
.addOnFailureListener { e ->
Log.w(TAG, "Error adding document", e)
}
}
This creates the following in Firestore:
Now I try to receive my data using a function provided by the docs. However, I am stuck on turning the data back into a list containing my data classes that I just created. I tried a few things and I didn’t manage to resolve the issue reading the docs.
fun readFromDB(collectionName: String){
db.collection(collectionName)
.get()
.addOnSuccessListener { result ->
for (document in result) {
Log.d(TAG, "${document.id} => ${document.data}")
var values = ArrayList(document.data.values).toList()
//--------------------------------------------------
//I have no clue what to do starting from this point.
//--------------------------------------------------
println(values)
}
}
.addOnFailureListener { exception ->
Log.w(TAG, "Error getting documents.", exception)
}
}
Printing out the result which is a hashMap gives me:
[[{moodLevel=0, imageId=0, text=Title 1}, {moodLevel=1, imageId=0, text=Title 2}, {moodLevel=0, imageId=0, text=Title 3}]]
Question:
How can I turn this result into a list of objects again?
Tried a few things but nothing worked. Also read through a few threads here and didn’t find an answer that could apply to my use case. Any help would be appreciated. Sorry for this question if it’s really obvious in its solution.
Edit
After some tinkering following a guide from Mr Mamo I did this:
- Add a data class
JournalEntryFirebaseHolder
which looks like this
data class JournalEntryFirebaseHolder (
var journalEntryList: MutableList<JournalEntry>? = null
)
- Change the way I push my data into Firestore using the following function
fun createUserWithUID(UID:String){
val docData: MutableMap<String, Any> = HashMap()
docData["entries"] = Arrays.asList(
JournalEntry("Title 1", 0, 0, "1"),
JournalEntry("Title 2", 0, 1, "2"),
JournalEntry("Title 3", 0, 0, "3")
)
db.collection("entries")
.document("user1")
.set(docData)
.addOnFailureListener { e ->
Log.w(TAG, "Error adding document", e)
}
}
This creates the following in Firestore:
- Recieve data using the following function like this
fun readFromDB(UID: String){
val rootRef = FirebaseFirestore.getInstance()
val applicationsRef = rootRef.collection("entries")
val applicationIdRef = applicationsRef.document("user1")
applicationIdRef.get().addOnCompleteListener { task: Task<DocumentSnapshot> ->
if (task.isSuccessful) {
val document = task.result
if (document.exists()) {
val resultJournalEntries = document.toObject(JournalEntryFirebaseHolder::class.java)?.journalEntryList
//--------
//This returns null
//--------
println(resultJournalEntries)
//--------
//This returns the following
//{entries=[{moodLevel=0, imageId=0, text=Title 1, id=1}, {moodLevel=1, imageId=0, id=2, text=Title 2}, {moodLevel=0, imageId=0, id=3, text=Title 3}]}
//--------
println(document.data)
}
}
}
}
- My
JournalEntry
data class looks like this
data class JournalEntry (val text : String, val imageId : Int, val moodLevel : Int, val id :String )
Problem: I made some progress but I am still struggling to convert the data I receive back into JournalEntry Objects. Any help is appreciated.
Solution
Thank you Mr Mamo for helping me find this solution! Here is what I did:
- Change my
JournalEntry
data class like this to include default values. This is because my data class needs a no-arg constructor else my code will throw a exception later on. Read this question for more information.
data class JournalEntry (val text : String = "", val imageId : Int = 0, val moodLevel : Int = 0, val id :String = "0")
- In my readData function read my data like this:
fun readFromDB(){
val rootRef = FirebaseFirestore.getInstance()
val applicationsRef = rootRef.collection("entries")
val applicationIdRef = applicationsRef.document("user1")
applicationIdRef.get().addOnCompleteListener { task: Task<DocumentSnapshot> ->
if (task.isSuccessful) {
val document = task.result
if (document.exists()) {
//This returns an ArrayList with JournalEntry Objects!
val entries = document.toObject(JournalEntryFirebaseHolder::class.java)?.entries
}
}
}
JournalEntryFirebaseHolder
basically holds the received list that I fetch from Firestore. You can find detailed information in my -Edit- Section as well as in the marked answer.
2
Answers
You can convert your list to a HashMap as follows:
So you would have a map with a title as your key and the content of the object. (Since the titles can be repeated, I recommend assigning an ID so that you associate the object with that ID)
Then you just upload your map by doing:
Then to get it:
Or if you don’t want to modify what you already have, when you get the data, take it out of the array, since you would be doing nested lists, just leave:
And I recommend installing the Gson library to convert the objects to Json and vice versa, and you just get it:
Unfortunately, Firestore doesn’t provide a
toList()
method inside the DocumentSnapshot class. However, there is a really simple solution that can solve this issue. So to get the content of the "data" array and convert it into a list ofJournalEntry
objects, then you should simply create a new class that contains that specific list like this:Now to read the data, you can simply use:
I have also written an article on this topic called: