How retrieve values from an object on Cloud Firestore? Swift
Solution 1
Your readArray code is SUPER close. Just need to add code to read the individual fields within the document
func readArray()
self.db.collection("places").getDocuments { (snapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in snapshot!.documents {
let docId = document.documentID
let latMax = document.get("latMax") as! String
let latMin = document.get("latMin") as! String
let lonMax = document.get("lonMax") as! String
let lonMin = document.get("lonMin") as! String
print(docId, latMax, latMin, lonMax, lonMin)
}
}
}
The problem in the original question is the structure of the database. Here's a structure that will match the code in my answer and will be better suited for what the OP wants to accomplish.
The structure in the question has multiple places listed under one collection - that's OK but it groups the places together. If we change that to have one place per collection, it makes iterating over them and getting to the data much easier.
Solution 2
I think your places model have references to two objects bestBuy and house. So, the retrieval approach would be to retrieve the data from and store in the object only. Means you can directly set all the data in plcaes model. Then you can call getter methods of bestBuy and house to retrieve the data as you want. Here is a sampe code (here it is retrieving only one document) but you can apply the same for all documents by iterating a for loop and converting each document to object:-
let docRef = db.collection("cities").document("BJ")
docRef.getDocument { (document, error) in
if let city = document.flatMap({
$0.data().flatMap({ (data) in
return City(dictionary: data)
})
}) {
print("City: \(city)")
} else {
print("Document does not exist")
}
}
But according to firestore documentation the best way to store nested objects is creating a subcollection and then storing it in its document.
Solution 3
Some clarification since the iOS Firestore documentation is, IMO, light in many areas: there are two ways to retrieve the values from a document field (once the document has been gotten)--using a Firestore method (per the documentation) and using Swift's native method of getting values from dictionaries.
let query = Firestore.firestore().collection("zipCodes").whereField("california", arrayContains: 90210)
query.getDocuments { (snapshot, error) in
guard let snapshot = snapshot,
error == nil else {
return print("error: \(error!)")
}
guard !snapshot.isEmpty else {
return print("results: 0")
}
for doc in snapshot.documents {
// using firestore's convention
if let array = doc.get("zipCodes") as? [Int] {
if array.contains(90211) {
// doc contains both zip codes
}
}
// using swift's convention
if let array = doc.data()["zipCodes"] as? [Int] {
if array.contains(90211) {
// doc contains both zip codes
}
}
}
}
Personally, I would use as much of Firestore's framework as possible for safety and predictability and, therefore, use get()
for all field retrieval.
Robby
Updated on June 07, 2022Comments
-
Robby about 2 years
I'm quite new on
Firestore
andFirebase
libraries. Can someone explain how could I retrieve the fields from myobject
and stored in a variable on my code? I'm trying to access all thelatMin
,latMax
,lonMin
, andlonMax
from each object in my Firestore, as well if is a way to retrieve each field with the same name (ex.latMin
from place 1 and 2). I don't know if this is possible or maybe there is a better way to have organized myFirebase
.Here is my Cloud Firebase: Here is the image for my Firestore, requested in the comments.
place 1: //This is an Object in my Firestore //Field = Number : Value ----> This is how object is orginazed latMax : 39.727 latMin : 39.726 lonMax : -121.7997 lonMin : -121.8003 place 2: latMax : 39.7559 latMin : 39.755 lonMax : -122.1988 lonMin : -122.1992
I was able to access the objects without any problem, this is the function I'm using to read the documents on my Firestore:
import UIKit import FirebaseFirestore import Firebase import CoreLocation class SecondViewController: UIViewController, CLLocationManagerDelegate { //Creating access to locationManager var locationManager : CLLocationManager! @IBOutlet weak var latLabel: UILabel! @IBOutlet weak var lonLabel: UILabel! @IBOutlet weak var place: UILabel! @IBOutlet weak var placeImage: UIImageView! //Storing the pass data that we got from the firt View var lonStore = String() var latStore = String() var fireLon = String() var fireLat = String() var lonNumberStore = Double() var latNumberStore = Double() var fireLonMax = Double() var fireLatMax = Double() var fireLonMin = Double() var fireLatMin = Double() override func viewDidLoad() { //Here goes some code to display on the SecondViewController readArray() } func readArray() { let placeRef = Firestore.firestore().collection("places") placeRef.getDocuments { (snapshot, error) in guard let snapshot = snapshot else { print("Error \(error!)") return } for document in snapshot.documents { let documentId = document.documentID let latMax = document.get("latMax") as! String //Getting a nil error print(documentId, latMax) //This print all objects } } }
I'm missing something and I know it, the problem is that I can't find any reference of what I need to do in this case, I had read the documentation like 50 times and I can't find the solution. Thanks for taking the time to read my post.
-
Raj almost 6 yearsFirwstore does not provide any method to fetch data of particular field of a document. You have to first fetch all the documents of a collection and then you can get the fields you want.
-
Robby almost 6 years@Raj I try many different ways to accomplish accessing the fields after I fetch my documents but returns
nil
every time or my app crash! The way I try is accessing like anarray[0]
etc. -
Raj almost 6 yearsCan you plz add the complete code where you are calling the function and also the screenshot of the database
-
Jay almost 6 years@Raj I know what your statement means, but to clarify a bit; You do not have to fetch all of the documents of a collection - you can fetch a single document and then access it's fields. Or query for a set of documents to which you can access individual fields within each document, or retrieve all the documents and access their fields. The example here Get Document will retrieve the contents of a single 'SF' document to which the individual fields can be accessed.
-
Robby almost 6 years@raj I just add the screenshot of my Firesbase as well litlte changes on my code!
-
Robby almost 6 years@Jay Is giving me a
nil
error! :( -
Raj almost 6 yearsCan u share the Model class @Robby
-
Robby almost 6 years@Jay I edit the rest of the code with everything that I have, I hope that will give you more information.
-
-
Robby almost 6 yearsI try to access the field following your code and returns
nil
, I believe is accessing a wrong field or maybe I'm missing something. I edit the code on my post! -
Jay almost 6 years@Robby AH - ok. I see the issue. The way the database is structured is the problem. You have multiple places listed under each collection and in this case I think you want a collection representing one place. I've updated my answer with a structure that will better suit what you are trying to do. The code I posted works with that structure
-
Jay almost 6 years@Robby If you really want to have all of the places listed under one collection, that can be done, but I think denormalizing the data one level would be appropriate since the top level collection is called 'places' anyway, it's children should be each place.
-
Robby almost 6 yearsthis helps me a lot, the only problem that I have right now is how I suppose to struct my Firestore. I have to find the best way to struct my database and be able to get the best result! Any recommendation to learn a little bit more of Firestore! Thank you