Mise en route de Cloud Firestore pour iOS

Les codeurs mobiles profitent depuis de nombreuses années de la base de données en temps réel Firebase en temps réel de la plate-forme Mobile Backend en tant que service (MBaaS) de Google, les aidant à se concentrer sur la création de fonctionnalités pour leurs applications sans avoir à se soucier de l'infrastructure et de la base de données. En facilitant le stockage et la conservation des données dans le cloud, ainsi que l’authentification et la sécurité, Firebase permet aux codeurs de se concentrer sur le côté client.. 

L'année dernière, Google a annoncé une nouvelle solution de base de données back-end, Cloud Firestore, conçue à partir de rien, avec la promesse d'une plus grande évolutivité et d'une plus grande intuitivité. Cependant, cela a créé une certaine confusion quant à sa place par rapport au produit phare de Google, Firebase Realtime Database. Ce tutoriel décrira les différences entre les deux plates-formes et les avantages distincts de chacune. Vous apprendrez à travailler avec les références de documents Firestore, ainsi qu'à lire, écrire, mettre à jour et supprimer des données en temps réel, en créant une simple application de rappels..

Objectifs de ce tutoriel

Ce tutoriel vous exposera à Cloud Firestore. Vous apprendrez à exploiter la plate-forme pour la synchronisation et la persistance de la base de données en temps réel. Nous couvrirons les sujets suivants:

  • Qu'est-ce que Cloud Firestore?
  • le modèle de données Firestore
  • mise en place de Cloud Firestore
  • création et utilisation de références Cloud Firestore
  • lire des données en temps réel depuis Cloud Firestore
  • création, mise à jour et suppression de données
  • filtrage et requêtes composées

Connaissance supposée

Ce didacticiel suppose que vous avez eu une certaine exposition à Firebase et qu’un arrière-plan se développe avec Swift et Xcode..

Qu'est-ce que Cloud Firestore??

Comme Firebase Realtime Database, Firestore propose aux développeurs mobiles et Web une solution cloud multi-plateformes pour la conservation des données en temps réel, indépendamment de la latence du réseau ou de la connectivité Internet, ainsi qu'une intégration transparente à la suite de produits Google Cloud Platform. Outre ces similitudes, il existe des avantages et des inconvénients distincts qui différencient les uns des autres.. 

Modèle de données

Au niveau fondamental, la base de données Realtime stocke les données dans un grand arbre JSON hiérarchique monolithique, tandis que Firestore organise les données dans des documents et des collections, ainsi que dans des sous-collections. Cela nécessite moins de dénormalisation. Le stockage de données dans une seule arborescence JSON présente les avantages de la simplicité s’agissant de répondre à des exigences simples en matière de données; cependant, il devient plus lourd à l’échelle lorsque vous travaillez avec des données hiérarchiques plus complexes.. 

Support hors ligne

Les deux produits offrent une prise en charge hors ligne, mettant en cache activement les données dans les files d'attente en cas de latence ou d'absence de connexion réseau synchronisant les modifications locales vers l'arrière-train lorsque cela est possible. Firestore prend en charge la synchronisation hors ligne pour les applications Web en plus des applications mobiles, tandis que la base de données Realtime ne permet que la synchronisation mobile..

Requêtes et transactions 

Realtime Database ne prend en charge que les fonctionnalités de tri et de filtrage limitées. Vous pouvez uniquement trier ou filtrer au niveau d'une propriété, mais pas les deux, dans une seule requête. Les requêtes sont également profondes, ce qui signifie qu'elles renvoient une grande sous-arborescence de résultats. Le produit ne prend en charge que les opérations d'écriture et de transaction simples nécessitant un rappel d'achèvement.. 

Firestore, d’autre part, introduit des requêtes d’index avec un tri et un filtrage composés, vous permettant de combiner des actions pour créer des filtres et un tri en chaîne. Vous pouvez également exécuter des requêtes superficielles renvoyant des sous-collections au lieu de la totalité de la collection que vous obtiendriez avec Realtime Database. Les transactions sont de nature atomique, que vous envoyiez une opération de traitement par lots ou en mode individuel, les transactions se répétant automatiquement jusqu'à leur conclusion. En outre, la base de données Realtime ne prend en charge que les transactions d’écriture individuelles, tandis que Firestore autorise les opérations par lots de manière atomique..

Performance et évolutivité

Comme vous vous en doutez, la base de données en temps réel est relativement robuste et présente une latence faible. Cependant, les bases de données sont limitées à des régions uniques, sous réserve de disponibilité par zone. Firestore, quant à lui, héberge des données horizontalement sur plusieurs zones et régions afin de garantir une disponibilité, une évolutivité et une fiabilité globales. En fait, Google a promis que Firestore serait plus fiable que la base de données en temps réel.. 

Une autre lacune de la base de données Realtime est la limitation à 100 000 utilisateurs simultanés (100 000 connexions simultanées et 1 000 écritures / seconde dans une base de données unique), après quoi vous devez partager votre base de données (divisez votre base de données en plusieurs bases de données) afin de prendre en charge davantage d'utilisateurs. . Firestore évolue automatiquement sur plusieurs instances sans que vous ayez à intervenir. 

Conçu dès le départ avec une évolutivité à l’esprit, Firestore dispose d’une nouvelle architecture schématique qui réplique les données sur plusieurs régions, prend en charge l’authentification et gère d’autres problèmes liés à la sécurité, le tout dans son SDK côté client. Son nouveau modèle de données est plus intuitif que celui de Firebase, ressemblant davantage à d'autres solutions de base de données NoSQL comparables telles que MongoDB, tout en fournissant un moteur d'interrogation plus robuste.. 

Sécurité 

Enfin, comme vous le savez dans nos précédents didacticiels, Realtime Database gère la sécurité au moyen de règles en cascade avec des déclencheurs de validation distincts. Cela fonctionne avec les règles de base de données Firebase, en validant vos données séparément. Firestore, en revanche, fournit un modèle de sécurité plus simple, mais plus puissant, tirant parti des règles de sécurité Firestore Cloud et de la gestion des identités et des accès (IAM), avec validation automatique des données..

Le modèle de données Firestore

Firestore est une base de données NoSQL basée sur des documents, composée de collections de documents contenant des données. Comme il s'agit d'une base de données NoSQL, vous n'obtiendrez pas de tables, de lignes et d'autres éléments que vous trouverez dans une base de données relationnelle, mais plutôt des ensembles de paires clé / valeur que vous trouverez dans les documents.. 

Vous créez implicitement des documents et des collections en affectant des données à un document. Si le document ou la collection n'existe pas, il sera automatiquement créé pour vous, car la collection doit toujours être le premier (noeud) racine. Voici un exemple de schéma de tâches simple du projet sur lequel vous allez travailler prochainement, comprenant la collection de tâches, ainsi que de nombreux documents contenant deux champs, le nom (chaîne) et un indicateur indiquant si la tâche est terminée (booléen)..

Décomposons chacun des éléments pour mieux les comprendre. 

Des collections

Synonyme de tables de base de données dans le monde SQL, les collections contiennent un ou plusieurs documents. Les collections doivent être les éléments racine de votre schéma et ne peuvent contenir que des documents, pas d'autres collections. Cependant, vous pouvez vous référer à un document qui à son tour se réfère à des collections (sous-collections).

Dans le diagramme ci-dessus, une tâche est composée de deux champs primitifs (nom et fait) ainsi que d'une sous-collection (sous-tâche) composée de deux champs primitifs distincts.. 

Les documents

Les documents se composent de paires clé / valeur, les valeurs ayant l'un des types suivants: 

  • champs primitifs (tels que chaînes, nombres, booléens)
  • objets imbriqués complexes (listes ou tableaux de primitives)
  • sous-collections

Les objets imbriqués sont également appelés cartes et peuvent être représentés comme suit dans le document. Voici un exemple d'objet et de tableau imbriqués:

ID: 2422892 // nom primitif: “N'oubliez pas d'acheter du lait” détail: // note d'objet imbriqué: "Il s'agit d'une tâche permettant d'acheter du lait en magasin" created: 2017-04-09 échéance: 2017-04-10 fait: false notifier: ["2F22-89R2", "L092-G623", "H00V-T4S1"]… 

Pour plus d'informations sur les types de données pris en charge, consultez la documentation de Google relative aux types de données. Ensuite, vous allez configurer un projet pour travailler avec Cloud Firestore.

Mise en place du projet

Si vous avez déjà travaillé avec Firebase, cela devrait vous être familier. Sinon, vous devrez créer un compte dans Firebase et suivre les instructions de la section "Configuration du projet" de notre didacticiel précédent, Prise en main de l'authentification Firebase pour iOS. . 

Pour suivre ce tutoriel, clonez le référentiel de projet du tutoriel. Ensuite, incluez la bibliothèque Firestore deen ajoutant ce qui suit à votre Podfile:

pod 'Firebase / Core' pod 'Firebase / Firestore'

Entrez ce qui suit dans votre terminal pour construire votre bibliothèque:

installation de pod

Ensuite, passez à Xcode et ouvrez le .xcworkspace fichier. Accédez au AppDelegate.swift fichier et entrez les informations suivantes dans le application: didFinishLaunchingWithOptions: méthode:

FirebaseApp.configure ()

Dans votre navigateur, accédez à la console Firebase et sélectionnez le Base de données onglet à gauche. 

Assurez-vous de sélectionner l’option à Démarrer en mode test de sorte que vous n’ayez aucun problème de sécurité pendant que nous expérimentons et que vous teniez compte de l’avis de sécurité lorsque vous mettez votre application en production. Vous êtes maintenant prêt à créer une collection et des exemples de documents..

Ajout d'une collection et d'un exemple de document

Pour commencer, créez une collection initiale, les tâches, en sélectionnant le Ajouter une collection bouton et nommer la collection, comme illustré ci-dessous:

Pour le premier document, vous allez laisser l'ID de document vierge, ce qui générera automatiquement un ID pour vous. Le document se composera simplement de deux champs: prénom et terminé.

Enregistrez le document et vous devriez pouvoir confirmer la collecte et le document avec l'ID généré automatiquement:

Avec la base de données configurée avec un exemple de document dans le nuage, vous êtes prêt à commencer à implémenter le SDK Firestore dans Xcode..

Création et utilisation de références de base de données

Ouvrez le MasterViewController.swift fichier dans Xcode et ajoutez les lignes suivantes pour importer la bibliothèque:

classe Firebase import MasterViewController: UITableViewController @IBOutlet faible var addButton: UIBarButtonItem! Documents var privés: [DocumentSnapshot] = [] tâches var publiques: [Tâche] = [] écouteur var privé: ListenerRegistration!… 

Ici, vous créez simplement une variable d’écoute qui vous permettra de déclencher une connexion à la base de données en temps réel en cas de changement. Vous créez également un DocumentSnapshot référence qui tiendra l'instantané de données temporaire.

Avant de continuer avec le contrôleur de vue, créez un autre fichier swift, Task.swift, qui représentera votre modèle de données:

Importer la tâche de base de la structure nom_variable: Chaîne nom_fil fait: Bool id_Vid: Chaîne var dictionnaire: [Chaîne: N'importe quel] return ["nom": nom, "fait": fait] extension Tâche init? (dictionnaire: [Chaîne: Any], id: String) garde laisser name = dictionary ["name"] comme? String, let done = dictionnaire ["done"] comme? Bool else return nil self.init (name: name, done: done, id: id)

L'extrait de code ci-dessus inclut une propriété de commodité (dictionnaire) et une méthode (init) qui faciliteront le remplissage de l'objet modèle. Revenez dans le contrôleur de vue et déclarez une variable de définition globale qui contraindra la requête de base aux 50 premières entrées de la liste des tâches. Vous supprimerez également le programme d’écoute une fois la variable de requête définie, comme indiqué dans didSet propriété ci-dessous:

fileprivate func baseQuery () -> Requête return Firestore.firestore (). collection ("Tasks"). limit (to: 50) fileprivate var query: Requête? didSet if let listener = auditeur listener.remove () écrasera func viewDidLoad () super.viewDidLoad () self.query = baseQuery () écrasera func viewWillDisappear (_ animé: Bool) super.viewWillDisappear ( animé) self.listener.remove ()

Lecture de données en temps réel depuis Cloud Firestore

Avec la référence du document en place, en viewWillAppear (_animated: Bool), associez l'écouteur que vous avez créé précédemment aux résultats de l'instantané de la requête et récupérez une liste de documents. Ceci est fait en appelant la méthode Firestore query? .addSnapshotListener:

self.listener = query? .addSnapshotListener (documents, erreur) dans guard garde let snapshot = documents else print ("Erreur lors de l'extraction des documents: \ (erreur!)") return let results = snapshot.documents.map (document ) -> Tâche dans si let task = Tâche (dictionnaire: document.data (), id: document.documentID) tâche de retour else fatalError ("Impossible d'initialiser le type \ (Task.self) avec le dictionnaire \ (document. data ()) ") self.tasks = résultats self.documents = snapshot.documents self.tableView.reloadData ()

La fermeture ci-dessus assigne la instantané.documents en mappant le tableau de manière itérative et en l’enveloppant dans un nouveau Tâche objet d'instance de modèle pour chaque élément de données de l'instantané. Donc, avec seulement quelques lignes, vous avez réussi à lire toutes les tâches du nuage et à les affecter au système global. les tâchestableau. 

Pour afficher les résultats, renseignez les éléments suivantsTableViewméthodes déléguées:

redéfinit func numberOfSections (dans tableView: UITableView) -> Int return 1 substitut func tableView (_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int retour tasks.count remplacera func tableView (_ tableView: UITableView, UITFView, cellForRowAt, indexPath : IndexPath) -> UITableViewCell let cell = tableView.dequeueReusableCell (withIdentifier: "Cell", pour: indexPath) let item = tasks [indexPath.row] cell.textLabel! .Text = item.name cell.textLabel! .TextColor = item.done == false? UIColor.black: cellule de retour UIColor.lightGray

A ce stade, construisez et exécutez le projet et dans le simulateur, vous devriez pouvoir observer les données apparaissant en temps réel. Ajoutez des données via la console Firebase et vous devriez les voir apparaître instantanément dans le simulateur d'application.. 

Création, mise à jour et suppression de données

Après avoir lu avec succès le contenu du back-end, vous allez ensuite créer, mettre à jour et supprimer des données. L'exemple suivant expliquera comment mettre à jour des données, en utilisant un exemple artificiel dans lequel l'application vous permettra uniquement de marquer un élément comme étant effectué en appuyant sur la cellule. Noter la collection.document (ID de l'article) .updateData (["done":! item.done]) La propriété de fermeture, qui référence simplement un ID de document spécifique, met à jour chacun des champs du dictionnaire:

override func tableView (_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) let élément = tâches [indexPath.row] let collection = Firestore.firestore (). collection ("Tâches") collection.document (item.id) .updateData ( ["done":! item.done,]) err in if let err = err print ("Erreur lors de la mise à jour du document: \ (err)") else print ("Document mis à jour avec succès") tableView.reloadRows (à: [indexPath], avec: .automatic)

Pour supprimer un élément, appelez le document(ID de l'article).effacer() méthode:

redéfinissez func tableView (_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool return true remplacez func tableView (_ tableView: UITableView, commit éditionStyle: UITableViewCellEditingStyle, pourRowAt indexPath: IndexPath) si (éditionStyle ==.). let item = tasks [indexPath.row] _ = Firestore.firestore (). collection ("Tâches"). document (item.id) .delete ()

La création d’une nouvelle tâche implique l’ajout d’un nouveau bouton dans votre Storyboard et la connexion de son IBAction au contrôleur de vue, créant un addTask (_ expéditeur :) méthode. Lorsqu'un utilisateur appuie sur le bouton, une feuille d’alerte s’affiche, lui permettant d’ajouter un nouveau nom de tâche:

collection ("Tasks"). addDocument (data: ["name": textFieldReminder.text ?? "tâche vide", "done": false]) 

Complétez la dernière partie de l'application en saisissant les éléments suivants:

@IBAction func addTask (_ expéditeur: Any) laissez alertVC: UIAlertController = UIAlertController (titre: "Nouvelle tâche", message: "De quoi voulez-vous vous souvenir?", PreferredStyle: .alert) alertVC.addTextField (UITextField) dans  let cancelAction = UIAlertAction.init (titre: "Annuler", style: .destructive, gestionnaire: nil) alertVC.addAction (cancelAction) // Fermeture de l’action d’alerte let addAction = UIAlertAction.init (title: "Ajouter", style:. par défaut) (UIAlertAction) -> Nul dans let textFieldReminder = (alertVC.textFields? .first)! comme UITextField, db = Firestore.firestore () var docRef: DocumentReference? = nil docRef = db.collection ("Tasks"). addDocument (data: ["name": textFieldReminder.text ?? "tâche vide", "done": false]) err in if let let = err print ( "Erreur lors de l'ajout du document: \ (err)") else print ("Document ajouté avec l'ID: \ (docRef! .DocumentID)") alertVC.addAction (addAction) present (alertVC, animé: true, complétion: nul)

Générez et exécutez l'application une fois de plus et, lorsque le simulateur apparaît, essayez d'ajouter quelques tâches, en en marquant quelques unes comme terminées, et testez enfin la fonction de suppression en supprimant certaines tâches. Vous pouvez vérifier que les données stockées ont été mises à jour en temps réel en basculant sur votre console de base de données Firebase et en observant la collection et les documents..

Filtrage et requêtes composées

Jusqu'à présent, vous n'avez travaillé qu'avec une requête simple, sans aucune capacité de filtrage spécifique. Pour créer des requêtes légèrement plus robustes, vous pouvez filtrer par des valeurs spécifiques en utilisant un oùField clause:

docRef.whereField (“name”, isEqualTo: searchString)

Vous pouvez commander et limiter les données de votre requête en utilisant le commandé par: ) et limite à: ) méthodes comme suit:

docRef.order (par: "nom"). limit (5)

Dans l’application FirebaseDo, vous avez déjà utilisé limite avec la requête de base. Dans l'extrait de code ci-dessus, vous avez également utilisé une autre fonctionnalité, les requêtes composées, dans laquelle l'ordre et la limite sont chaînés. Vous pouvez chaîner autant de requêtes que vous le souhaitez, comme dans l'exemple suivant:

docRef .whereField (“name”, isEqualTo: searchString) .whereField (“done”, isEqualTo: false) .order (par: "name") .limit (5)

Conclusion

Dans ce didacticiel, vous avez exploré le nouveau produit MBaaS de Google, Cloud Firestore, et créé une application simple de rappel de tâches qui montre à quel point il est facile pour vous de conserver, de synchroniser et d'interroger vos données dans le cloud. Vous avez découvert la structure du schéma de données de Firestore par rapport à la base de données Firebase Realtime, comment lire et écrire des données en temps réel, ainsi que la mise à jour et la suppression de données. Vous avez également appris à exécuter des requêtes simples et composées et à filtrer des données.. 

Cloud Firestore a été créé dans le but de fournir la robustesse de la base de données Firebase Realtime, sans les nombreuses limitations que les développeurs de téléphones mobiles ont dû endurer, en particulier en ce qui concerne l'évolutivité et les requêtes. Firestore ne fait qu'effleurer la surface, et il vaut certainement la peine d'explorer certains des concepts les plus avancés, tels que la pagination de données avec des curseurs de requête, la gestion des index et la sécurisation de vos données..