Learn Courses My Dashboard

Fetching sub collection from firebase and assigning it to an array

Hi

I’m having a problem assigning data to an array when fetching a sub collection from firebase. Here’s is my code and the explanation of what’s happening. any help will be appreciate it.

These are my models

import Foundation
import CoreLocation

struct KnownRegions: Identifiable {
    
    var id: String?
    var centerLat:Double?
    var centerLong:Double?
    var radius: Double?
    
    
}




struct VisitedRegions: Identifiable {
    
    var visitedCounter: Int = 0
    var id: String?
    var centerLat:Double?
    var centerLong:Double?
    var radius: Double?
    
    
}


struct UserTrips: Identifiable {
    
    var id:String = ""
    var traveledDistance: Double = 0.0
    var tripDate: String = ""
    var pointsPerTrip: Int = 0
    var suddenBreak: [SuddenBreak] = []
    var speeding: [Speeding] = [Speeding]()
    
}

struct SuddenBreak {
    
   // var suddenBrake: Bool?
    var streetName: String = ""
    var dateSuddenBreake: String = ""
    
}

struct Speeding: Identifiable {
   // var speeding: Bool?
    var id: String = ""
    var streetName: String = ""
    var dateSpeeding: String = ""
}

class User {
    
    var id: String = "" 
    var name: String = ""
    var email: String = ""
    var totalPoints: Int = 0
    var totalTraveledDistance: Double = 0.0
    var visitedRegions: [VisitedRegions] = []
    var knownRegions: [KnownRegions] = []
    var userTrips: UserTrips = UserTrips()
}

and this is the fetching data method

 func getUserTrips() {
        
        guard Auth.auth().currentUser != nil else {
            return
        }
        
        let db = Firestore.firestore()
        
        let ref = db.collection(Constants.users).document(Auth.auth().currentUser!.uid)
        
        let userTripCollection = ref.collection(Constants.userTripCollections)
        
        
        userTripCollection.getDocuments { querySnapshot, error in
            
            
            
            guard error == nil && querySnapshot != nil else {
                return
            }
            
            var userTripArrayq = [UserTrips]()
            
            
            for docs in querySnapshot!.documents {
                
                var u = UserTrips()
                var speedingArray = [Speeding]()
                
                u.traveledDistance = docs[Constants.traveledDistance] as! Double
                u.pointsPerTrip = docs[Constants.pointsPerTrip] as! Int
                u.tripDate = docs[Constants.tripDate] as! String
                u.id = docs.documentID
                
               
                
                    
                let speedingCollection = userTripCollection.document(u.id).collection(Constants.speeding)


                    speedingCollection.getDocuments { snapshot, error in

                        for speedingDocs in snapshot!.documents {
                            var speeding = Speeding()
                            

                            speeding.streetName = speedingDocs["streetName"] as! String
                            speeding.dateSpeeding = speedingDocs["dateSpeeding"] as! String
                            speeding.id = speedingDocs[speedingDocs.documentID] as? String ?? UUID().uuidString
                            speedingArray.append(speeding)
                           

                        }

                        u.speeding = speedingArray
                        // if I print this array at this point everything is ok but once it goes out the "for speedingDocs loop" it shows that the array is empty so I can't assign the speeding array subcollection to the userTripsCollection array
                        
                    }

               
                print(u.speeding) // here it shows that the array is empty
                
                
                
                
                let suddenBreakCollection = userTripCollection.document(u.id).collection(Constants.suddenBreak)

                suddenBreakCollection.getDocuments { snapshot, error in

                    guard error == nil && snapshot != nil else {
                        return
                }

                    for suddenDocs in snapshot!.documents {
                        var suddenBreak = SuddenBreak()

                        suddenBreak.streetName = suddenDocs["streetName"] as! String
                        suddenBreak.dateSuddenBreake = suddenDocs["dateSuddenBreake"] as! String

                        u.suddenBreak.append(suddenBreak)

                    }



            }
                
                
                userTripArrayq.append(u) // here it works perfectly
                
        }
            
            
                
                self.userTripsArray = userTripArrayq  // here it's ok
                
                
            
        
    }
        
       
}

Any help from you guys will be appreciate it

Can you show what the object looks like in Firebase?

Hi mikaelacaron. Thanks for your reply. I’ve already solved this issue. Thanks again for your help

Can you post your solution?
It may help someone else!

1 Like

Hi Mikaela. There wasn’t really a solution. I don’t know why when I tried to print the array it didn’t show me anything. What I did was calling the values of the array in one of my views and they appeared fine. Now I have another problem and I would like you to help me with that. I’m trying to collect and save my data into firebase.

What I’m doing is once the user stop driving and arrived to his destination I call locationManager.startUpdatingLocation() in order to make my counter count. Once the counter reach its final number and a boolean is true, I collect the information of the trip and save it to the database as well as I send a notification to the user with some info. The problem is that the location manager start updatingLocation update the location twice per second and that makes that the notification fire twice as well as my data save twice in the database. Please see below my code

This is the location Manager func

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
            // Gives us the location of the user
            
     
            locationManager.pausesLocationUpdatesAutomatically = false

            locationManager.startMonitoringSignificantLocationChanges()

            locationManager.allowsBackgroundLocationUpdates = true

            locationManager.showsBackgroundLocationIndicator = false

            locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation

            locationManager.activityType = .automotiveNavigation

            locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
            
           
           
            let userLocation = locations.first
            
            userHeading = userLocation?.course ?? CLLocationDirection()
            
            
            
            
            
            if  locationManager.location?.speed ?? CLLocationSpeed() <= 2 && foregroundStartedTrip == true {

                tripEnded()

            }
           
            if locationManager.location?.speed  ?? CLLocationSpeed() >= 3 {

                checkLogin()

                if loggedIn {
                    
                    terminatedTripCounter = 0

                    foregroundLocationServices()
                    
                    if suddenBreak() {
                        
                        points -= 200
                        
                        suddenBrake.dateSuddenBreake = locationManager.location?.timestamp.formatted(date: .abbreviated, time: .complete) ?? ""
                        
                        getSpeedLimit(location: location)
                        
                        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [self] in
                            
                            suddenBrake.streetName = speedLimitInfo[0].name ?? ""
                            
                            suddenBrakeArray.append(suddenBrake)
                        }
                    }
                    
                }
                
            }          



            if locationManager.location?.speed ?? CLLocationSpeed() >= 10 {
                
                if loggedIn {
                    
                    calculateTrip()
                    
                }

            }

and this is the func that collect the data


    func tripEnded() {

        
 
        
        let constantTripCounter = 10
            
            if user.knownRegions.count == 0 {
                    
                   getNewRegion()
                    
                    if  (newRegion.center.latitude != lastRegion.center.latitude || newRegion.center.longitude != lastRegion.center.longitude) && locationManager.location?.speed ?? CLLocationSpeed() <= 2 {
                        
                        locationManager.startUpdatingLocation()
                        
                        terminatedTripCounter += 1
                        
                        
                            
                        if terminatedTripCounter == constantTripCounter && foregroundStartedTrip == true  {
                                
                                locationManager.stopUpdatingLocation()
                                
                                foregroundStartedTrip = false
                                
                                notifications.scheduleStartedTripNotifications(points: points)

                                totalPoints = totalPoints + points
                                pointsPerTrip = points

                                traveledDistanceTrip = traveledDistance * 0.000621
                                totalTraveledDistance += traveledDistance

                                tripDate = locationManager.location?.timestamp.formatted(date: .abbreviated, time: .complete) ?? ""

                                 let visitRegion = newRegion

                                 getVisitedRegions(circularRegion: visitRegion)
                                 getKnownRegions()

                                 saveData()


                                print("Travel Distance: \(String(describing: travelDistanceArray))")
                                print("Date: \(dateArray)")

                                DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [self] in
                                    
                                    points = 0
                                    
                                    traveledDistance = 0

                                    speedingArray = [Speeding]()
                                    
                                }
                        }
                    }
          }

I’ll really appreciate your help on this