English 中文(简体)
Swift Firestore GeoFire - How to properly use for best performance in location app with large database?
原标题:

Hi I am working on a location based app (ie uber, doordash, tinder, bumble, etc) that is expected to have a large database of users from around the world. I am new to both Xcode + swift and firebase and I m currently using Firestore. I have recently found out about GeoFire and using a hash but it seems that most of the information I am finding is outdated.

What I am trying to understand is the proper way to structure my database and code for best performance and lower costs.

My current database looks something like this:

FirestoreDB -> Users -> UserId -> Document Data = [ Latitude, Longitude, GeoHash ]

And the code I am using is from Firebase docs (*I do not have any collections/documents currently for cities, countries etc.) -

// Compute the GeoHash for a lat/lng point
let latitude = 51.5074
let longitude = 0.12780
let location = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)

let hash = GFUtils.geoHash(forLocation: location)

// Add the hash and the lat/lng to the document. We will use the hash
// for queries and the lat/lng for distance comparisons.
let documentData: [String: Any] = [
    "geohash": hash,
    "lat": latitude,
    "lng": longitude
]

let londonRef = db.collection("cities").document("LON")
londonRef.updateData(documentData) { error in
    // ...
}

And in the same doc, the code to query -

// Find cities within 50km of London
let center = CLLocationCoordinate2D(latitude: 51.5074, longitude: 0.1278)
let radiusInM: Double = 50 * 1000

// Each item in  bounds  represents a startAt/endAt pair. We have to issue
// a separate query for each pair. There can be up to 9 pairs of bounds
// depending on overlap, but in most cases there are 4.
let queryBounds = GFUtils.queryBounds(forLocation: center,
                                      withRadius: radiusInM)
let queries = queryBounds.map { bound -> Query in
    return db.collection("cities")
        .order(by: "geohash")
        .start(at: [bound.startValue])
        .end(at: [bound.endValue])
}

var matchingDocs = [QueryDocumentSnapshot]()
// Collect all the query results together into a single list
func getDocumentsCompletion(snapshot: QuerySnapshot?, error: Error?) -> () {
    guard let documents = snapshot?.documents else {
        print("Unable to fetch snapshot data. (String(describing: error))")
        return
    }

    for document in documents {
        let lat = document.data()["lat"] as? Double ?? 0
        let lng = document.data()["lng"] as? Double ?? 0
        let coordinates = CLLocation(latitude: lat, longitude: lng)
        let centerPoint = CLLocation(latitude: center.latitude, longitude: center.longitude)

        // We have to filter out a few false positives due to GeoHash accuracy, but
        // most will match
        let distance = GFUtils.distance(from: centerPoint, to: coordinates)
        if distance <= radiusInM {
            matchingDocs.append(document)
        }
    }
}

// After all callbacks have executed, matchingDocs contains the result. Note that this
// sample does not demonstrate how to wait on all callbacks to complete.
for query in queries {
    query.getDocuments(completion: getDocumentsCompletion)
}

According to this, for my situation I would need to create a collection for each city/location(?) and query all the "userId" documents in the database, which of course wouldn t be optimal. I see the functions for saving a key and retrieving by key, such as -

  geoFire.getLocationForKey("firebase-hq") 

but I don t see the key being added to Firestore and I m not sure how this would even work in my situation since any location and users locations needs to be dynamic and needs to update on the go? So how can that be used in a dynamic way so documents can be grouped by key(?) and queries ran against those documents based on the key that matches the current location s hash?

I m unsure what is the best approach on this, there are a lot of popular location based apps out there so I m wondering how do they handle it. Any suggestions is appreciated, thanks.

EDIT: To clarify further: I am trying to use Firestore geohashes but I am looking for a better way rather than querying every document in the database.

问题回答

暂无回答




相关问题
How to change out-of-focus text selection color in Xcode?

Okay, I ll bite. I ve got really pleasant code/window colors set up in Xcode. Ordinarily, my selection color is very visible. When I am doing a project search and iterating through the results, ...

Iphone NSTimer Issue

Hi I am new to objective c. I am trying to make an app for iphone. I have a button on my view, and the click on which the function playSound is called. This is working properly. It does plays the ...

Include a .txt file in a .h in C++?

I have a number of places where I need to re-use some template code. Many classes need these items In a .h could I do something like: #include <xxx.txt> and place all of this code in the ....

Iterating over string/strlen with umlauted characters

This is a follow-up to my previous question . I succeeded in implementing the algorithm for checking umlauted characters. The next problem comes from iterating over all characters in a string. I do ...

Xcode open two editor windows with same file

Is it possible to open the same file in two separate windows in Xcode. I can open a file in one window and the same file in the main Xcode editor window, but I wanted two separate fulltime editor ...

Forcing code signing refresh in Xcode

In our environment, we share resources across multiple projects and platforms. When building for iPhone, only a subset of those resources are needed. Since that subset is still considerable, we have ...

热门标签