iosswiftfirebasegoogle-cloud-platformgoogle-cloud-firestore

What is the best practice for decoding Firestore documents in a listener for Swift 5?


I'm using a couple of Firestore listeners in my app and I'm wondering what is the preferred way to decode Cloud Firestore documents in those listener closures? Is it better to use .data(as:), Firestore.Decoder().decode(), or querySnapshot.documents.compactMap? I have successfully used all three but I would like more information on which is best to use when. An example of each is below:

let document = try documentSnapshot.data(as: SummaryDocument.self)

let documentData = documentSnapshot.data()
let decodedDocument = try Firestore.Decoder().decode(SummaryDocument.self, from: documentData!)

let documents = querySnapshot.documents.compactMap { document in
   try? document.data(as: SummaryDocument.self)
}

From most of what I've read, it seems that .data(as: or Firestore.Decoder() is more useful if you're going after a single document and need more control over the data. It would also seem that it's recommended to use .data(as: as the preferred method in most cases because it's simpler to use, handles document ID, and is possibly more efficient. In the case of multiple documents however, .compactMap seems to be the recommended way to go.

Is this the case? Can anyone confirm this and maybe give more guidance?


Solution

  • When mapping documents from Cloud Firestore to Swift structs, you should generally use the Codable protocol - it allows you to map documents with just a single line of code instead of having to write the mapping code for each single attribute individually.

    For mapping a single document, use try document.data(as: YourType.self).

    When mapping multiple documents (e.g. the result of a query), you will still use try document.data(as: YourType.self), but inside a loop that iterates over all the documents in the result set of your query. An elegant way to do this is to use compactMap, as it automatically drops nil values (which may be the result of trying to map from a document to a struct that doesn’t have matching fields).

    This page in the documentation has a lot more details and provides lots of examples:

    https://firebase.google.com/docs/firestore/solutions/swift-codable-data-mapping