So currently, my client (iOS/Swift) is fetching documents by filtering on a whereField(...) and then further filtering down the results based on a few other fields. This means that some objects are fetched, then discarded, wasting precious resourced and bandwidth!
Can I do this complex filtering on a firestore cloud function than somehow parse the filtered results into the same firestore object on the client? To be clear, I know how to write cloud functions that fetch and return documents, I am more interested to understand the transport method to the client.
Code snippet to provide some context:
static func unmatchedChatsHelper(cursor: Any?, promise: @escaping (Result<UnmatchedChatsCursorResponse, Never>) -> Void) {
let earliestEventTime = Date()
// (1) Filtering done on backend.
var query = Firestore.firestore().collection("chats")
.whereField("eventTime", isGreaterThan: earliestEventTime)
.order(by: "eventTime")
.order(by: "createdAt", descending: true)
if let cursor = cursor as? DocumentSnapshot {
query = query.start(afterDocument: cursor)
}
query.getDocuments { (querySnapshot, error) in
guard let querySnapshot = querySnapshot else {
fatalError("Query snapshot failed: \(error?.localizedDescription ?? "no error")")
}
let transformedModels = querySnapshot.documents.compactMap { (chatQueryDocumentSnapshot) -> ChatModelFirebase? in
do {
return try chatQueryDocumentSnapshot.data(as: ChatModelFirebase.self)!
} catch let error {
logEvent(AnalyticsEventDidDropDocument, [
"document_id": chatQueryDocumentSnapshot.documentID
], error)
return nil
}
}
let me = Auth.auth().currentUser!.uid
// (2) Filtering done on client! This means some chats are retrieved unnecessarily.
let unmatchedChats = transformedModels.filter {
!$0.participants.contains(me)
&& $0.numParticipants < 6
&& !$0.declinedParticipants.contains(me)
&& $0.isDebug == DebugGating.isDebugBuild()
}
let cursor = querySnapshot.documents.last
promise(.success(UnmatchedChatsCursorResponse(models: unmatchedChats, cursor: cursor as Any)))
}
}
I have three options:
- [My Choice/Best Option] Same as above, but use
Firestore.Decoderto parse resultsChatModelFirebase. - [Parsing Logic is Dangerous] Do the query on a cloud function, return JSON, and manually parse the results into
ChatModelFirebase. - [Too Costly To Do] Update my firestore document structure for all queries to be done via the
whereField(..)but this is complex sincewhereFieldis limited in its options.
Anything else I a missing? Is there a better way to do this?