Structures
The following structures are available globally.
-
A property wrapper type that marks a
DocumentReference?
orString?
field to be populated with a document identifier when it is read.Apply the
@DocumentID
annotation to aDocumentReference?
orString?
property in aCodable
object to have it populated with the document identifier when it is read and decoded from Firestore.Important
The name of the property annotated with
@DocumentID
must not match the name of any fields in the Firestore document being read or else an error will be thrown. For example, if theCodable
object has a property namedfirstName
annotated with@DocumentID
, and the Firestore document contains a field namedfirstName
, an error will be thrown when attempting to decode the document.Example Read:
struct Player: Codable { @DocumentID var playerID: String? var health: Int64 }
let p = try! await Firestore.firestore() .collection(“players”) .document(“player-1”) .getDocument(as: Player.self) print(“(p.playerID!) Health: (p.health)”)
// Prints: “Player: player-1, Health: 95”
- Important: Trying to encode/decode this type using encoders/decoders other than Firestore.Encoder throws an error. - Important: When writing a Codable object containing an `@DocumentID` annotated field, its value is ignored. This allows you to read a document from one path and write it into another without adjusting the value here.
Declaration
Swift
@propertyWrapper public struct DocumentID<Value: DocumentIDWrappable & Codable>: StructureCodingUncodedUnkeyed
extension DocumentID: Codable
extension DocumentID: Equatable where Value: Equatable
extension DocumentID: Hashable where Value: Hashable
-
Wraps an
Optional
field in aCodable
object such that when the field has anil
value it will encode to a null value in Firestore. Normally, optional fields are omitted from the encoded document.This is useful for ensuring a field is present in a Firestore document, even when there is no associated value.
Declaration
Swift
@propertyWrapper public struct ExplicitNull<Value>
extension ExplicitNull: Equatable where Value: Equatable
extension ExplicitNull: Hashable where Value: Hashable
extension ExplicitNull: Encodable where Value: Encodable
extension ExplicitNull: Decodable where Value: Decodable
-
A property wrapper that marks an
Optional<Timestamp>
field to be populated with a server timestamp. If aCodable
object being written contains anil
for an@ServerTimestamp
-annotated field, it will be replaced withFieldValue.serverTimestamp()
as it is sent.Example:
struct CustomModel { @ServerTimestamp var ts: Timestamp? }
Then writing
CustomModel(ts: nil)
will tell server to fillts
with current timestamp.Declaration
Swift
@propertyWrapper public struct ServerTimestamp<Value>: Codable where Value: ServerTimestampWrappable & Codable
extension ServerTimestamp: Equatable where Value: Equatable
extension ServerTimestamp: Hashable where Value: Hashable
-
A property wrapper that listens to a Firestore collection.
In the following example,
FirestoreQuery
will fetch all documents from thefruits
collection, filtering only documents whoseisFavourite
attribute is equal totrue
, map members of result set to theFruit
type, and make them available via the wrapped valuefruits
.struct ContentView: View { @FirestoreQuery( collectionPath: "fruits", predicates: [.whereField("isFavourite", isEqualTo: true)] ) var fruits: [Fruit] var body: some View { List(fruits) { fruit in Text(fruit.name) } } }
FirestoreQuery
also supports returning aResult
type. The.success
case returns an array of elements, whereas the.failure
case returns an error in case mapping the Firestore documents wasn’t successful:struct ContentView: View { @FirestoreQuery( collectionPath: "fruits", predicates: [.whereField("isFavourite", isEqualTo: true)] ) var fruitResults: Result<[Fruit], Error> var body: some View { if case let .success(fruits) = fruitResults { List(fruits) { fruit in Text(fruit.name) } } else if case let .failure(error) = fruitResults { Text("Couldn't map data: \(error.localizedDescription)") } }
Alternatively, the projected value of the property wrapper provides access to the
error
as well. This allows you to display a list of all successfully mapped documents, as well as an error message with details about the documents that couldn’t be mapped successfully (e.g. because of a field name mismatch).struct ContentView: View { @FirestoreQuery( collectionPath: "mappingFailure", decodingFailureStrategy: .ignore ) private var fruits: [Fruit] var body: some View { VStack(alignment: .leading) { List(fruits) { fruit in Text(fruit.name) } if $fruits.error != nil { HStack { Text("There was an error") .foregroundColor(Color(UIColor.systemBackground)) Spacer() } .padding(30) .background(Color.red) } } } }
Internally,
@FirestoreQuery
sets up a snapshot listener and publishes any incoming changes via an@StateObject
.The projected value of this property wrapper provides access to a configuration object of type
FirestoreQueryConfiguration
which can be used to modify the query criteria. Changing the filter predicates results in the underlying snapshot listener being unregistered and a new one registered.Button("Show only Apples and Oranges") { $fruits.predicates = [.whereField("name", isIn: ["Apple", "Orange]] }
This property wrapper does not support updating the
wrappedValue
, i.e. you need to use Firestore’s other APIs to add, delete, or modify documents.Declaration
Swift
@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) @propertyWrapper public struct FirestoreQuery<T> : DynamicProperty