Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How retrieve values from an object on Cloud Firestore? Swift

I'm quite new on Firestore and Firebase libraries. Can someone explain how could I retrieve the fields from my object and stored in a variable on my code? I'm trying to access all the latMin, latMax, lonMin, and lonMax 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 my Firebase.

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.

like image 671
Robby Avatar asked Aug 31 '18 08:08

Robby


3 Answers

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.

enter image description here

like image 62
Jay Avatar answered Nov 19 '22 18:11

Jay


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.

like image 22
Raj Avatar answered Nov 19 '22 20:11

Raj


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.

like image 1
liquid LFG UKRAINE Avatar answered Nov 19 '22 19:11

liquid LFG UKRAINE