Firestore logo

Getting Started With Cloud Firestore for iOS

Mobile coders have been taking advantage of Google’s Mobile Backend as a Service (MBaaS) platform Firebase Realtime Database for many years, helping them focus on building features for their apps without having to worry about the back-end infrastructure and database. By making it easy to store and persist data in the cloud and take care of authentication and security, Firebase allows coders to focus on the client side. 

Last year, Google announced yet another back-end database solution, Cloud Firestore, built from the ground up with the promise of greater scalability and intuitiveness. However, this introduced some confusion as to its place in relation to Google’s already existing flagship product, Firebase Realtime Database. This tutorial will outline the differences between the two platforms and the distinct advantages of each. You will learn how to work with Firestore document references, as well as reading, writing, updating and deleting data in real time, by building a simple reminders app.

Objectives of This Tutorial

This tutorial will expose you to Cloud Firestore. You’ll learn how to leverage the platform for real-time database persistence and synchronization. We’ll cover the following topics:

  • what Cloud Firestore is
  • the Firestore data model
  • setting up Cloud Firestore
  • creating and working with Cloud Firestore references
  • reading data in real time from Cloud Firestore
  • creating, updating and deleting data
  • filtering and compound queries

Assumed Knowledge

This tutorial assumes you have had some exposure to Firebase and a background developing with Swift and Xcode.

What Is Cloud Firestore?

Like Firebase Realtime Database, Firestore provides mobile and web developers with a cross-platform cloud solution to persist data in real time, regardless of network latency or internet connectivity, as well as seamless integration with the Google Cloud Platform suite of products. Along with these similarities, there are distinct advantages and disadvantages that differentiate one from the other. 

Data Model

On a fundamental level, Realtime Database stores data as one large, monolithic, hierarchical JSON tree, whereas Firestore organizes data in documents and collections, as well as sub-collections. This requires less denormalization. Storing data in one JSON tree has the benefits of simplicity when it comes to working with simple data requirements; however, it becomes more cumbersome at scale when working with more complex hierarchical data. 

Offline Support

Both products offer offline support, actively caching data in queues when there is latent or no network connectivity—synchronising local changes back to the back end when possible. Firestore supports offline synchronisation for web apps in addition to mobile apps, whereas the Realtime Database only enables mobile synchronization.

Queries and Transactions 

Realtime Database only supports limited sorting and filtering capabilities—you can only sort or filter on a property level, but not both, in a single query. Queries are also deep, meaning they return a large sub-tree of results back. The product only supports simple write and transaction operations which require a completion callback. 

Firestore, on the other hand, introduces index queries with compound sorting and filtering, allowing you to combine actions to create chain filters and sorting. You can also execute shallow queries returning sub-collections in lieu of the entire collection you would get with Realtime Database. Transactions are atomic in nature, whether you send a batch operation or single, with transactions repeating automatically until concluded. Additionally, Realtime Database only supports individual write transactions, whereas Firestore affords batch operations atomically.

Performance and Scalability

The Realtime Database, as you would expect, is quite robust and has low latency. However, databases are restricted to single regions, subject to zonal availability. Firestore, on the other hand, houses data horizontally across multiple zones and regions to ensure true global availability, scalability, and reliability. In fact, Google has promised that Firestore will be more reliable than Realtime Database. 

Another shortcoming of the Realtime Database is the limitation to 100,000 concurrent users (100,000 concurrent connections and 1,000 writes/second in a single database) after which you would have to shard your database (split your database into multiple databases) in order to support more users. Firestore automatically scales across multiple instances without you having to intervene. 

Designed from the ground up with scalability in mind, Firestore has a new schematic architecture that replicates data across multiple regions, takes care of authentication, and handles other security-related matters all within its client-side SDK. Its new data model is more intuitive than Firebase’s, more closely resembling other comparable NoSQL database solutions like MongoDB, while providing a more robust querying engine. 

Security 

Finally, Realtime Database, as you know from our previous tutorials, manages security through cascading rules with separate validation triggers. This works with Firebase Database Rules, validating your data separately. Firestore, on the other hand, provides a simpler yet more powerful security model taking advantage of Cloud Firestore Security Rules and Identity and Access Management (IAM), with data validation excepted automatically.

  • Mobile Development
    Firebase Security Rules
    Chike Mgbemena

The Firestore Data Model

Firestore is a NoSQL document-based database, consisting of collections of documents, each of which contains data. As it’s a NoSQL database, you won’t get tables, rows, and other elements you would find in a relational database, but instead sets of key/value pairs that you would find within documents. 

You create documents and collections implicitly by assigning data to a document, and if the document or collection doesn’t exist, it will automatically be created for you, as the collection always has to be the root (first) node. Here is a simple Tasks example schema of the project you will be working on shortly, consisting of the Tasks collection, as well as numerous documents containing two fields, the name (string), and a flag for whether the task is done (boolean).

simple Tasks example schema of the project

Let’s decompose each of the elements so you can understand them better. 

Collections

Synonymous with database tables in the SQL world, collections contain one or more documents. Collections have to be the root elements in your schema and can only contain documents, not other collections. However, you can refer to a document which in turn refers to collections (sub-collections).

Diagram of document and collections

In the diagram above, a task consists of two primitive fields (name and done) as well as a sub-collection (sub-task) which consists of two primitive fields of its own. 

Documents

Documents consist of key/value pairs, with the values having one of the following types: 

  • primitive fields (such as strings, numbers, boolean)
  • complex nested objects (lists or arrays of primitives)
  • sub-collections

Nested objects are also called maps and can be represented as follows, within the document. The following is an example of a nested object and array, respectively:

For more information on the supported data types, refer to Google’s Data Types documentation. Next, you will set up a project to work with Cloud Firestore.

Setting Up the Project

If you have worked with Firebase before, a lot of this should be familiar to you. Otherwise, you will need to create an account in Firebase and follow the instructions in the ‘Set Up the Project’ section of our previous tutorial, Get Started With Firebase Authentication for iOS . 

To follow along with this tutorial, clone the tutorial project repo. Next, include the Firestore library by adding the following to your Podfile:

Enter the following in your terminal to build your library:

Next, switch to Xcode and open up the .xcworkspace file. Navigate to the AppDelegate.swift file and enter the following within the application:didFinishLaunchingWithOptions: method:

In your browser, go to the Firebase console and select the Database tab on the left. 

Database tab in the Firebase console

Make sure you select the option to Start in Test Mode so that you don’t have any security issues while we experiment, and heed the security notice when you do move your app into production. You are now ready to create a collection and some sample documents.

Adding a Collection and Sample Document

To start off, create an initial collection, Tasks, by selecting the Add Collection button and naming the collection, as illustrated below:

naming the collection

For the first document, you are going to leave the Document ID blank, which will auto-generate an ID for you. The document will simply consist of two fields: name and done.

Document with two fields

Save the document, and you should be able to confirm the collection and document along with the auto-generated ID:

collection and document with the auto-generated ID

With the database set up with a sample document in the cloud, you are ready to start implementing the Firestore SDK in Xcode.

Creating & Working With Database References

Open up the MasterViewController.swift file in Xcode and add the following lines to import the library:

Here you are simply creating a listener variable that will allow you to trigger a connection to the database in real time when there is a change. You are also creating a DocumentSnapshot reference that will hold the temporary data snapshot.

Before continuing with the view controller, create another swift file, Task.swift, which will represent your data model:

The code snippet above includes a convenience property (dictionary) and method (init) that will make populating the model object easier. Switch back to the view controller, and declare a global setter variable which will constrain the base query to the top 50 entries in the tasks list. You will also be removing the listener once you set the query variable, as denoted in the didSet property below:

Reading Data in Real Time From Cloud Firestore

With the document reference in place, in viewWillAppear(_animated: Bool), associate the listener you created earlier with the results of the query snapshot, and retrieve a list of documents. This is done by calling the Firestore method query?.addSnapshotListener:

The closure above assigns the snapshot.documents by mapping the array iteratively and wrapping it to a new Task model instance object for each data item in the snapshot. So with just a few lines, you have successfully read in all the tasks from the cloud and assigned them to the global tasks array. 

To display the results, populate the following TableView delegate methods:

At this stage, build and run the project and in the Simulator you should be able to observe data appearing in real time. Add data via the Firebase console and you should see it appear instantaneously in the app simulator. 

Data appearing in the app simulator

Creating, Updating and Deleting Data

After successfully reading content from the back-end, next you will create, update and delete data. The next example will illustrate how to update data, using a contrived example where the app will only let you mark an item as done by tapping on the cell. Note the collection.document(item.id).updateData(["done": !item.done]) closure property, which simply references a specific document ID, updating each of the fields in the dictionary:

To delete an item, call the document(item.id).delete() method:

Creating a new task will involve adding a new button in your Storyboard and connecting its IBAction to the view controller, creating an addTask(_ sender:) method. When a user presses the button, it will bring up an alert sheet where the user can add a new task name:

Complete the final part of the app by entering the following:

Build and run the app once more and, when the simulator appears, try adding in a few tasks, as well as marking a few as done, and finally test the delete function by removing some tasks. You can confirm that the stored data has been updated in real time by switching over to your Firebase database console and observing the collection and documents.

collection and documents in the console

Filtering and Compound Queries

So far, you’ve only worked with a simple query, without any specific filtering capabilities. To create slightly more robust queries, you can filter by specific values by making use of a whereField clause:

You can order and limit your query data, by making use of the order(by: ) and limit(to: ) methods as follows:

In the FirebaseDo app, you already made use of limit with the base query. In the above snippet, you also made use of another feature, compound queries, where both the order and limit are chained together. You can chain as many queries as you want, such as in the following example:

Conclusion

In this tutorial, you explored Google’s new MBaaS product, Cloud Firestore, and in the process created a simple task reminder app that demonstrates how easy it is for you to persist, synchronize, and query your data in the cloud. You learned about Firestore’s data schema structure in comparison to Firebase Realtime Database, and how to read and write data in real time, as well as updating and deleting data. You also learned how to perform simple as well as compound queries, and how to filter data. 

Cloud Firestore was created with the aim of providing the robustness of Firebase Realtime Database without many of the limitations mobile developers had to endure, especially as pertains to scalability and querying. We only scratched the surface of what you can accomplish with Firestore, and it’s certainly worth exploring some of the more advanced concepts, such as Paginating Data with Query Cursors, Managing Indexes, and Securing Your Data.

Powered by WPeMatico

Leave a Comment

Scroll to Top