I'm trying to model a database schema for Firestore. How can I create this database model?
This is my recipe data class
data class Foods(
var foodId:String?,
var foodName:String,
var foodCategory:String,
var foodCalory:Int,
var foodIngredients:String,
var foodRecipe:String,
var foodCookingTime:Int,
var foodImg:String?)
My Users Id getting this
val user : FirebaseUser? = auth?.currentUser
val userID: String = user?.uid.toString()
As I see in your screenshot, your document (vp0q ...) holds an array of Foods objects. If you want to be able to map that document to an object of a particular class, you should consider using the following class declarations:
data class User (recipe: Array<Foods>)
Now, to read that document, you should use the following reference:
val uid = FirebaseAuth.getInstance().currentUser?.uid
val rootRef = FirebaseFirestore.getInstance()
val usersRef = rootRef.collection("users")
usersRef.document(uid).get()
.addOnSuccessListener { document ->
if (document != null) {
val recipe = document.toObject<Foods>().recipe
//Do what you need to do with your recipe array
} else {
Log.d(TAG, "No such document")
}
}
.addOnFailureListener { exception ->
Log.d(TAG, "get failed with ", exception)
}
Related
Would like to reduce the number of reads in my app with Firestore. So I created a document in my collection with the following structure to hold values for 10 "records", that I will get with a single read - since the size of this document is pretty decent, no worries about the 1MB limit size for a single document. I am updating the content of this document with cloud functions.
name of collection: helperz
name of document: top10
field name in top10: tresholdCounter - this I need to check if a single map should be added to top10 or not
field name in top10: top10 . . array of maps
helperz/top10/tresholdCounter
helperz/top10/top10/0/author
helperz/top10/top10/0/name
helperz/top10/top10/0/url
helperz/top10/top10/1/author
helperz/top10/top10/1/name
helperz/top10/top10/1/url
helperz/top10/top10/2/author
helperz/top10/top10/2/name
helperz/top10/top10/2/url
helperz/top10/top10/3/author
helperz/top10/top10/3/name
helperz/top10/top10/3/url
helperz/top10/top10/4/author
helperz/top10/top10/4/name
helperz/top10/top10/4/url
..
helperz/top10/top10/10/author
helperz/top10/top10/10/name
helperz/top10/top10/10/url
I have a data class . . like this:
data class MyClass(
var name: String? = null,
var url: String? = null,
var author: String? = null,
var counter: Int = 0,
var free: Boolean? = false,
var global: Boolean?=true,
var poses: ArrayList<MyPoze>? = null,
var docId: string? = null,
var category: ArrayList<String>? = null,
#get:PropertyName(CREATED)
#set:PropertyName(CREATED)
#ServerTimestamp var created: Timestamp? = null
)
There are some other fields as well, but for the purpose of this problem, that should be ok.
I have a code for retrieving data from Firestore (in my viewModel):
private fun getHelperzTop10() = viewModelScope.launch {
Log.d("MP23", "getHelperzTop10")
val docRef = db.collection("helperz").document("top10")
docRef.addSnapshotListener { snapshot, e ->
if (e != null) {
Log.w("MP23", "Listen failed.", e)
return#addSnapshotListener
}
if (snapshot != null && snapshot.exists()) {
val docSize = firestoreDocument.getSize(snapshot);
Log.d("MP23","docSize in Bytes: $docSize, in KB: ${docSize * 0.001}, in MB: ${docSize * 0.000001}"
)
val top10 = snapshot.data
Log.d("MP23", top10!!::class.simpleName.toString() )
if ("top10" in keys) {
val top10arr = top10["top10"] as ArrayList<MyClass>
Log.d("MP23", "we have top10 in top10")
Log.d("MP23", top10arr!!::class.simpleName.toString())
Log.d("MP23", top10arr.toString())
//// 👇 PROBLEM HERE ///
// here I need somehow to cast this array of maps as MyClass, but I am getting error:
// java.util.ArrayList cannot be cast to java.lang.MyClass
// or
// java.util.ArrayList cannot be cast to java.lang.Object[] - with some other versions
}
} else {
Log.d("MP23", "Current data: null")
}
}
}
If someone can suggest how can I cast result to MyClass, that would be great. In normal situation (where I have documents that I query against) nicely as single docs, I can easily do:
val singleRec = singleRec.toObject(MyClass::class.java)
If you want to get the top10 array as a List<MyClass>, the simplest solution that I can think of would be to create another class:
data class Document(
var top10: MutableList<MyClass>? = null
)
And read the content of the document like this:
docRef.get().addOnCompleteListener {
if (it.isSuccessful) {
val snapshot = it.result
snapshot?.let {
val document = snapshot.toObject(Document::class.java)
document?.let {
val top10 = document.top10
top10?.let {
for (myClass in top10) {
val name = myClass.name
Log.d("TAG", "$name")
}
}
}
}
} else {
it.exception?.message?.let { message ->
Log.d("TAG", message) //Never ignore potential errors!
}
}
}
I will also recommend you read the following resource for a better understanding:
How to map an array of objects from Cloud Firestore to a List of objects?
I'm trying to display data from Firestore and add it to a PieChart.
I can't figure out why I can't access my data
This is how data are stored in Firestore:
This is how I try to access it:
private val mFirestore = FirebaseFirestore.getInstance()
var chartdata: ArrayList<Measurements> = ArrayList()
private var chart: ScatterChart? = null
fun getCurrentUserID(): String {
val currentUser = FirebaseAuth.getInstance().currentUser
var currentUserID = ""
if (currentUser != null) {
currentUserID = currentUser.uid
}
return currentUserID
}
mFirestore.collection(Constants.MEASUREMENTS)
.whereEqualTo(Constants.USER_ID, getCurrentUserID())
.get()
.addOnSuccessListener { queryDocumentSnapshots ->
val userdata : ArrayList<Measurements> = ArrayList()
val weekdata = ArrayList<Measurements>()
if (!queryDocumentSnapshots.isEmpty) {
for (journals in queryDocumentSnapshots) {
val displayData: Measurements = journals.toObject(Measurements::class.java)
userdata.add(displayData)
Log.e("Data for chart", journals.toString())
}
And I get this error:
enter image description here
The data is being fetched precisely that's why you can see all the document names in the logcat but as you are logging DocumentSnapshot object, that's why you are seeing the data in unusual format. Try logging displayData variables like:
Log.d("Data for chart", displayData.activity) // Use Log.d instead of Log.e
or userdata as an array and it will work as desired.
I have a data class for data that come from user entries. İt is carrying this data to Firebase. This data class also includes documentId variable which is a empty string by default. I want to add document Id's that Firebase created automatically. I tried every way I could think of. But it takes default value in any way.
Here are the four code snippets about this issue. Data class, adding data activity, and retrieving data activity and their View Models.
Dataclass:
data class AnalyzeModel(
var concept: String?="",
var reason: String?="",
var result: String?="",
var rrRatio: Double?=0.0,
var tarih: Timestamp=Timestamp.now(),
var tradingViewUrl: String="",
var id : String="")
AddAnalyzeActivity, addData function:
fun addData(view: View) {
val tarih = com.google.firebase.Timestamp.now()
val rr = rrText.text.toString()
var doubleRR = rr.toDoubleOrNull()
if (doubleRR == null) { doubleRR = 0.0 }
val analyzeDTO = AnalyzeModel(
conceptText.text.toString(),
reasonForText.text.toString(),
resultAddingText.text.toString(),
doubleRR,
tarih,
chartImage.text.toString()
)
viewModel.save(analyzeDTO)
val intent = Intent(this, PairDetailActivity::class.java)
startActivity(intent)
finish()
}
AddAnalyze ViewModel, save function:
fun save(data: AnalyzeModel) {
database.collection(dbCollection!!).document("Specified").collection("Pairs")
.document(chosenPair!!)
.collection("Analysis")
.add(data)
.addOnFailureListener { exception ->
exception.printStackTrace()
Toast.makeText(getApplication(), exception.localizedMessage, Toast.LENGTH_LONG).show()
}
}
PairViewModel, retrieveData function:
private fun retrieveData() {
val docRef = collectionRef.orderBy("tarih", Query.Direction.DESCENDING)
docRef.addSnapshotListener { value, error ->
try {
if (value != null && !value.isEmpty) {
val allAnalysis= ArrayList<AnalyzeModel>()
val documents = value.documents
documents.forEach {
val analyze = it.toObject(AnalyzeModel::class.java)
if (analyze!=null){
allAnalysis.add(analyze)
}
}
list.value = allAnalysis
} else if (error != null) {
Toast.makeText(Application(), error.localizedMessage, Toast.LENGTH_LONG).show()
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
I want to add document IDs that Firebase created automatically.
To solve this, you only need to annotate the field with #DocumentId.
data class AnalyzeModel(
var concept: String?="",
var reason: String?="",
var result: String?="",
var rrRatio: Double?=0.0,
var tarih: Timestamp=Timestamp.now(),
var tradingViewUrl: String="",
#DocumentId 👈
var id : String=""
)
Be also sure to have the latest version of Firestore.
I would like to ask for help on how to retrieve data from Firestore for nested Array of Maps called "cities" into MutableList , which I then want to insert into recycler view, where the data from the “regions” are for the header and data “cities” for the regular list items.
Data for regions: MutableList , when I follow the procedure https://medium.com/firebase-tips-tricks/how-to-map-an-array-of-objects-from-cloud-firestore-to-a-list -of-objects-122e579eae10 by Alex Mamo, got fine, but data for: cities: MutableList , according same approach, is null (unable to retrive).
Can you please advise how to get data for “cities”?
P.s. somewhere I read the recommendation to iterate over "cities", but I have no idea how, please go straight for an example (ideally in Kontlin).
Code:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
…..
regionsRef.get().addOnCompleteListener { document ->
if (document.isSuccessful()) {
val documentSnapshot = document.result
// Retrieve array of maps for „regions“
val regions = documentSnapshot.toObject(RegionDocument::class.java)?.regions
// Retrieve array of maps for „cities“
val cities = documentSnapshot.toObject(CityDocument::class.java)?.cities
…
}
}
Data classes for object City:
data class City(
val cityNumber: Long? = null,
val cityName: String? = "" )
data class CityDocument(
var cities: MutableList<City>? = null)
Firestore structure:
To be able to get the data that corresponds to your document structure, you need three classes:
class Document {
var regions: MutableList<Region>? = null
}
class Region {
var cities: MutableList<City>? = null
var regionName: String? = null
var regionNumber: Long? = null
}
class City {
var cityName: String? = null
var cityNumber: Long? = null
}
And below you can find a solution for reading all cities:
val db = FirebaseFirestore.getInstance()
val docIdRef = db.collection("collName").document("docId")
docIdRef.get().addOnCompleteListener { task ->
if (task.isSuccessful) {
val document = task.result
if (document != null) {
val doc = document.toObject(Document::class.java)
if (doc != null) {
val regions = doc.regions
if (regions != null) {
for (region in regions) {
val cities = region.cities
//Do what you need to to do with your List<City>.
}
}
}
}
} else {
Log.d("TAG", task.exception!!.message!!) //Never ignore potential errors!
}
}
Now, simply replace collName and docId with the one you have in your database.
i need to get data from object (named "0") in a document in firestore, is that possible ?
this is my code now:
val db = FirebaseFirestore.getInstance()
val docRef = db.collection("accessories")
.document("brand0")
docRef.get().addOnCompleteListener(OnCompleteListener<DocumentSnapshot> { task ->
if (task.isSuccessful) {
val document = task.result
val group = document.get("0") as ArrayList<String>
}
but casting Any to Arraylist is not possible, any other way to get these data ?
It looks like 0 is a an object type field. That means it'll be represented locally as a Map type object with strings as the keys for the properties it contains.
After some trials and errors this is what worked for me in the end, but I am not sure why. I am using kotlin in my current project.
fun getOwner(userId: String) {
val db = Firebase.firestore
val docRef = db.collection("users").document(userId)
docRef.get()
.addOnSuccessListener { document ->
if (document != null) {
Log.d(TAG, "DocumentSnapshot data: ${document.data}")
val data = document.data as Map<String, String>
showOwnerName.text = data["name"]
} else {
Log.d(TAG, "No such document")
}
}
.addOnFailureListener { exception ->
Log.d(TAG, "get failed with ", exception)
}
}
I am converting the data I am getting to a map and this is how I am able to access its values.