I have a Contact
model which holds different attributes and lists of attributes. Now i want to store these in Firestore but with the lists as subcollections of the respective document.
A minimal example of the Contact
model looks like this (note that the list is excluded from the map):
class Contact(private val map: MutableMap<String, Any?>){
var nameDisplay:String? by map
var nickname:String? by map
var organisation:String? by map
val phones:ArrayList<Phone> = ArrayList()
}
With this representation in Firestore:
contacts:
contact1
nameDisplay = "Test"
nickname = "Test"
organisation = "some corp"
phones:
phone1
number = 8243525
label = "this guy"
phone2
number = 8243525433
label = "this guy"
contact2
....
I am looking for a way to best implement this behavior.
A working solution i found is with a secondary constructor where i can pass the collections seperately.
A desired implementation would be the default implementation for custom objects but with the above behavior:
var contact: Contact = documentSnapshot.toObject(Contact::class.java);
I think you're over engineering things. 😂 It would be much better Kotlin to have those properties be initialized from the constructor through parameters rather than the crazy delegation you're doing. (Though I must applaud you for pushing the language to its limits! 👍) As it so happens, the toObject
method works very nicely with those best practices. So your Contact
class should look something like this:
data class Contact(
@Exclude
@get:Keep
@set:Keep
var nameDisplay: String? = null,
@Exclude
@get:Keep
@set:Keep
var nickname: String? = null,
@Exclude
@get:Keep
@set:Keep
var organisation: String? = null,
@Exclude
@get:Keep
@set:Keep
@set:RestrictTo(RestrictTo.Scope.TESTS) // Hack b/c Firebase needs a setter but we don't
var phones: Map<String, Any?> = mapOf()
) {
val phoneObjects: MutableList<User> by lazy {
phones.parse() // Map them to your phone objects
}
}
That's a bit ugly but lets you use the toObject
method. A version with more code but that makes for a prettier data class would be manually passing in the parameters with snapshot.getString(...)
. However, if you really want to go the delegation route, I'm pretty sure you could just delegate the phones property to the map as well and then just pass in the snapshot data: Contact(snapshot.data)
.