-
Notifications
You must be signed in to change notification settings - Fork 7
Get Started with EasyFirestore
Welcome to EasyFirestore! π
EasyFirestore makes it fast and easy to:
- store, update, and retrieve documents quickly
- format data into documents and models that are ready to use with Firestore
- easily link child documents to a list of document ID's in a parent document
- retrieve a list of child documents given a list of ID's
- query for documents in a Swift-y manner
Benefits of EasyFirestore:
- π¦ Out-of-the-box cacheing saves your Firestore read count
- π€ Tackle database problems with ease using EasyFirestore's linking methods
- π Automatically track metrics such as document indexes using the
Singleton
protocol
In this page, you'll learn about:
- Setting up Firestore in Firebase Console β
- Create a Document Type β
- Sending a Document to Firestore β
- Linking to an Array of Document IDs β
- Retrieving Data from Firestore β
- Listening to Data Updates from Firestore β
- Querying for Documents in Firestore β
- The Document Cache β
- Managing One-Document Storage with Singletons β
To get started, you'll need to set up Firestore in your Firebase console. Find the Firestore tab and click the Get Started button.
Start in test mode, then click Next.
Pick a suitable database location, then click Enable.
You're good to go!
You'll first need to create a type that conforms to the Document
protocol:
class ExampleDocument: Document {
}
Every class that conforms to Document
has two required properties:
Property Name | Description |
---|---|
id |
The unique identifier of the document. |
dateCreated |
The date the document object was created. |
You'll need to add your own custom properties as well:
class ExampleDocument: Document {
// These properties are required by the Document protocol.
var id: String
var dateCreated: Date
// These properties are custom.
var foodName: String = ""
var calories: Int = 0
}
Once you have local instances of your Document, you can easily set your documents in Firestore using:
myDocument.set()
Equivalently, you can use the EasyFirestore.Storage
helper struct to send the document:
EasyFirestore.Storage.set(myDocument)
Most EasyFirestore methods like set()
have optional completion handlers, which are called when the operation is complete:
myDocument.set(completion: { error in
if let error = error {
print("An error occured! \(error.localizedDescription)")
} else {
// No problems setting the document in Firestore.
}
})
Conversely, the document can easily be deleted:
EasyFirestore.Removal.remove(myDocument)
Every document has an id
. If you wish to store a list of documents in another document type, it's useful to store a list of document IDs rather than the documents themselves to save on the size of a document. EasyFirestore makes document linking easy with pre-defined methods.
To see this in action, consider a Dealership
document type with a list of car ID's, cars
, of document type Car
:
class Dealership: Document {
// DocumentID is equivalent to a String, and is available when you import EasyFirebase.
var cars: [DocumentID]
// ...
}
class Car: Document {
var make: String
var model: String
var year: Int
// ...
}
We create a Car
object and link it to the dealership:
let car = new Car(make: "Toyota", model: "Corolla", year: 2017)
car.assign(toField: "cars", using: \.cars, in: dealership)
If you wish to link the object and send it, you can use setAssign(...)
:
car.setAssign(toField: "cars", using: \.cars, in: dealership)
Again, the EasyFirestore.Linking
helper struct can be used to do this.
βΉοΈ Quick Tip
EasyFirestore has many helper structs, including Storage, Retrieval, Querying, Updating, Removal, Linking, Cacheing, and Listening.You can use the EasyFirestore.Retrieval
helper struct to fetch a document of a given type:
EasyFirestore.Retrieval.get(id: someDocumentID, ofType: ExampleDocument.self) { document in
// Check that the document exists...
guard let document = document else { return }
// Run code related to the document here.
}
If you have a list of document IDs, you can fetch an array of documents of the same type:
EasyFirestore.Retrieval.get(ids: [docID1, docID2, docID3], ofType: ExampleDocument.self) { documents in
// If no documents are successfully retrieved, an empty array will be passed.
allDocs.append(documents)
}
Returning to our car/dealership example, we can also retrieve an array of child documents based on the parent document's ID array field:
EasyFirestore.Retrieval.getChildren(from: \.cars, in: dealership, ofType: Dealership.self, onFetch: { documents in
// Passes all of the car objects with IDs given by dealership.cars
})
Just as you can retrieve a document from Firestore once, you can also update a document locally whenever the document updates in Firestore.
EasyFirestore.Listening.listen(to: myDocumentID, ofType: ExampleDocument.self, key: "listenerKeyName", onUpdate: { document in
// Check the document exists...
guard let document = document else { return }
// The updated document is safely available here.
})
You can match an array of documents of a given type:
EasyFirestore.Querying.where(\ExampleDocument.name, .equals, "John Appleseed", completion: { documents in
// The queried documents are passed here.
})
There are various ways to match queries, called Comparison
s:
Comparison | Description |
---|---|
.equals |
The field value in Firestore equals the provided parameter |
.notEquals |
The field value in Firestore does not equal the provided parameter |
.lessThan |
The field value in Firestore is less than the provided parameter |
.lessEqualTo |
The field value in Firestore is less than or equal to the provided parameter |
.greaterThan |
The field value in Firestore is greater than the provided parameter |
.greaterEqualTo |
The field value in Firestore is greater than or equal to the provided parameter |
.contains |
The field value array in Firestore contains the provided parameter |
.containsAnyOf |
The field value array in Firestore contains any element of the provided parameter array |
.in |
The field value in Firestore is an element of the provided parameter array |
.notIn |
The field value in Firestore is not an element of the provided parameter array |
You can order and limit data, as well:
EasyFirestore.Querying.where(\.ExampleDocument.name, .in, ["Albert", "Ben", "Carey"], order: .ascending, limit: 8, completion: {
// A maximum of 8 documents, sorted in ascending order by the name field.
})
When using the order
parameter (.ascending
or .descending
), the documents are sorted by the provided field.
Additionally, you can chain multiple queries:
EasyFirestore.Querying.where((\ExampleDocument.age, .greaterThan, 18), (\.name, .lessThan, "L"), completion: { document in
// ...
})
When chaining, be sure to follow the Firestore Querying Limitations.
Sometimes you'll repeatedly access documents, which can spike your read count. To avoid this, EasyFirestore automatically caches documents for future retrieval.
Documents that are retrieved from Firestore are automatically cached. By default, documents fetched using EasyFirestore.Retrieval.get(...)
rely on the cache to get previously fetched documents. To bypass this, and to always receive up-to-date documents, pass false
to the useCache
parameter:
EasyFirestore.Retrieval.get(id: myDocumentId, ofType: ExampleDocument.self, useCache: false, completion: { document in
// ...
})
You can interact with the cache manual by using the EasyFirestore.Cacheing
helper struct.
// Manually store the document in the cache
EasyFirestore.Cacheing.register(myDocument)
// Manually retrieve the document from the cache
EasyFirestore.Cacheing.grab(myDocumentID, fromType: ExampleDocument.self)
It is possible to bypass cache usage entirely:
EasyFirebase.useCache = false
If you want to store data that is global to all users/devices, use a Singleton
. Singletons are of type Document
, but they have a few special properties. First, their id
is simply a name used to define the singleton.
class ExampleSingleton: Singleton {
// Required by the Singleton protocol
var id: SingletonName
var dateCreated: Date
// Custom, one-time properties
var totalUsers: Int = 0
var totalCars: Int = 0
}
To store the singleton properly, you must use the EasyFirestore.Storage.set(_:)
method:
EasyFirestore.Storage.set(mySingleton)
Such a singleton will be stored in a collection called "Singleton"
with a name based on the singleton's id
value.
EasyFirebase Wiki
β Installation
π Get Started with EasyAuth
π₯ Get Started with EasyFirestore
π Implement Sign In with Google
π Implement Sign In with Apple
π Using the Example Project
π Flowductive Website