绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
iOS版Cloud Firestore入门
2022-04-08 15:56:50

多年来,移动编码人员一直在利用Google的移动后端即服务 (MBaaS)平台Firebase实时数据库 ,从而帮助他们专注于为自己的应用程序构建功能,而不必担心后端基础结构和数据库。 通过简化在云中存储和持久存储数据并确保身份验证和安全性,Firebase允许编码人员将精力集中在客户端上。

去年,Google宣布了又一个后端数据库解决方案Cloud Firestore ,该解决方案是从头开始构建的,具有更大的可扩展性和直观性。 但是,这相对于Google已经存在的旗舰产品Firebase Realtime Database而言 ,引起了一些困惑。 本教程将概述两个平台之间的差异以及每个平台的独特优势。 您将通过构建简单的提醒应用程序来学习如何使用Firestore文档参考以及实时读取,写入,更新和删除数据。

本教程的目标

本教程将向您介绍Cloud Firestore 。 您将学习如何利用该平台实现实时数据库持久性和同步。 我们将讨论以下主题:

  • 什么是Cloud Firestore
  • Firestore数据模型
  • 设置Cloud Firestore
  • 创建和使用Cloud Firestore参考
  • 从Cloud Firestore实时读取数据
  • 创建,更新和删除数据
  • 过滤和复合查询

假设知识

本教程假定您已接触过Firebase,并具有使用Swift和Xcode进行开发的背景知识。

什么是Cloud Firestore?

Firebase Realtime Database一样,Firestore为移动和Web开发人员提供了一个跨平台的云解决方案,无论网络延迟或Internet连接如何,都可以实时持久存储数据,并且可以与Google Cloud Platform产品套件无缝集成。 伴随着这些相似之处,存在着明显的优缺点,它们彼此区别。

资料模型

从根本上讲,实时数据库将数据存储为一棵大的整体式分层JSON树,而Firestore将数据组织在文档,集合和子集合中。 这需要较少的非规范化。 在处理简单数据需求时,将数据存储在一个JSON树中具有简化的好处。 但是,在处理更复杂的分层数据时,规模化变得更加麻烦。

离线支援

两种产品都提供离线支持,在没有潜在的或没有网络连接的情况下主动将数据缓存在队列中—尽可能将本地更改同步回后端。 Firestore除了支持移动应用程序外,还支持Web应用程序的脱机同步,而Realtime Database仅支持移动同步。

查询和交易

实时数据库仅支持有限的排序和过滤功能-您只能在单个查询中在属性级别上进行排序或过滤,而不能同时在两者上进行排序或过滤。 查询也很深,这意味着它们会返回结果的大子树。 该产品仅支持需要完成回调的简单写入和事务操作。

另一方面,Firestore引入了具有复合排序和筛选功能的索引查询,使您可以组合操作以创建链式筛选器和排序功能。 您也可以执行浅层查询,以返回子集合来代替使用实时数据库获得的整个集合。 事务本质上是原子的,无论您发送批处理操作还是单次发送,事务都会自动重复直到结束。 此外,实时数据库仅支持单个写入事务,而Firestore原子地提供批处理操作。

性能和可伸缩性

正如您所期望的那样,实时数据库非常健壮并且具有低延迟。 但是,根据区域可用性,数据库仅限于单个区域。 另一方面,Firestore可在多个区域和区域中水平放置数据,以确保真正的全局可用性,可伸缩性和可靠性。 实际上,谷歌已经承诺Firestore会比实时数据库更可靠。

实时数据库的另一个缺点是限制了100,000个并发用户(单个数据库中有100,000个并发连接和1,000次写入/秒),之后您必须将数据库分片(将数据库拆分成多个数据库)以支持更多用户。 Firestore无需干预即可自动跨多个实例扩展。

Firestore从头开始设计,考虑到可伸缩性,它具有新的原理图体系结构,可跨多个区域复制数据,进行身份验证并在其客户端SDK中处理所有与安全性有关的事务。 它的新数据模型比Firebase更直观,与其他类似的NoSQL数据库解决方案(如MongoDB)更相似,同时提供了更强大的查询引擎。

安全

Firestore数据模型

Firestore是基于NoSQL文档的数据库,由文档集合组成,每个文档集合都包含数据。 由于它是NoSQL数据库,因此您将不会在关系数据库中找到表,行和其他元素,而会在文档中找到键/值对的集合。

您可以通过将数据分配给文档来隐式创建文档和集合,如果该文档或集合不存在,则将自动为您创建文档或集合,因为该集合始终必须是根(个)节点。 这是您不久将要处理的项目的简单Tasks示例架构,它由Tasks集合以及包含两个字段(名称(字符串)和是否完成任务的标志)的大量文档组成(布尔) 。

项目的简单Tasks示例架构

让我们分解每个元素,以便您可以更好地理解它们。

馆藏

集合与SQL世界中的数据库表同义,集合包含一个或多个文档。 集合必须是架构中的根元素,并且只能包含文档,而不能包含其他集合。 但是,您可以引用文档,而文档又引用集合(子集合)。

文件和托收图

在上图中,任务包含两个基本字段(名称和完成)以及一个子集合(子任务),该子集合包含其自身的两个基本字段。

文件资料

文档由键/值对组成,值具有以下类型之一:

  • 基本字段(例如字符串,数字,布尔值)
  • 复杂的嵌套对象(基元的列表或数组)
  • 子集合

嵌套对象也称为地图,可以在文档中表示如下。 以下是分别嵌套对象和数组的示例:

  1. ID: 2422892 //primitive
  2. name: “Remember to buy milk”
  3. detail: //nested object
  4. notes: "This is a task to buy milk from the store"
  5. created: 2017-04-09
  6. due: 2017-04-10
  7. done: false
  8. notify: ["2F22-89R2", "L092-G623", "H00V-T4S1"]
  9. ...

有关受支持的数据类型的更多信息,请参阅Google的设置项目

如果您以前曾经使用过Firebase,那么您应该对此很熟悉。 否则,您将需要在Firebase中创建一个帐户,并按照之前教程“ iOS的Firebase身份验证入门 ”中“设置项目”部分中的说明进行操作 。

要继续学习本教程,请克隆教程项目repo 。 接下来,通过以下方式添加Firestore库 将以下内容添加到您的Podfile中 :

  1. pod 'Firebase/Core'
  2. pod 'Firebase/Firestore'

在终端中输入以下内容以构建库:

pod install

接下来,切换到Xcode并打开.xcworkspace文件。 导航到AppDelegate.swift文件,然后在application:didFinishLaunchingWithOptions:方法中输入以下内容:

FirebaseApp.configure()

在浏览器中,转到Firebase控制台,然后选择左侧的“ 数据库”选项卡。

Firebase控制台中的“数据库”选项卡

确保选择“ 在测试模式下启动 ”选项,以便在我们进行实验时不会遇到任何安全问题,并且在将应用程序移入生产环境时请注意安全提示。 现在您可以创建一个集合和一些示例文档。

添加收集和样本文档

首先,通过选择Add Collection按钮并命名该集合来创建一个初始集合Tasks ,如下所示:

命名集合

对于个文档,您将文档ID保留为空白,这将为您自动生成一个ID。 该文档将仅包含两个字段: namedone 。

具有两个字段的文档

保存文档,您应该能够确认集合和文档以及自动生成的ID:

具有自动生成的ID的集合和文档

在云中使用示例文档设置数据库之后,您就可以开始在Xcode中实现Firestore SDK了。

创建和使用数据库引用

在Xcode中打开MasterViewController.swift文件,并添加以下行以导入库:

  1. import Firebase
  2. class MasterViewController: UITableViewController {
  3. @IBOutlet weak var addButton: UIBarButtonItem!
  4. private var documents: [DocumentSnapshot] = []
  5. public var tasks: [Task] = []
  6. private var listener : ListenerRegistration!
  7. ...

在这里,您只是创建一个侦听器变量,当发生更改时,该变量将允许您实时触发与数据库的连接。 您还将创建一个DocumentSnapshot引用,该引用将保存临时数据快照。

在继续使用视图控制器之前,创建另一个swift文件Task.swift ,它将代表您的数据模型:

  1. import Foundation
  2. struct Task{
  3. var name:String
  4. var done: Bool
  5. var id: String
  6. var dictionary: [String: Any] {
  7. return [
  8. "name": name,
  9. "done": done
  10. ]
  11. }
  12. }
  13. extension Task{
  14. init?(dictionary: [String : Any], id: String) {
  15. guard let name = dictionary["name"] as? String,
  16. let done = dictionary["done"] as? Bool
  17. else { return nil }
  18. self.init(name: name, done: done, id: id)
  19. }
  20. }

上面的代码段包含一个便捷属性(字典)和方法(init),这将使填充模型对象更加容易。 切换回视图控制器,并声明一个全局设置器变量,它将基本查询限制在任务列表的前50个条目中。 设置查询变量后,还将删除监听器,如下面的didSet属性所示:

  1. fileprivate func baseQuery() -> Query {
  2. return Firestore.firestore().collection("Tasks").limit(to: 50)
  3. }
  4. fileprivate var query: Query? {
  5. didSet {
  6. if let listener = listener {
  7. listener.remove()
  8. }
  9. }
  10. }
  11. override func viewDidLoad() {
  12. super.viewDidLoad()
  13. self.query = baseQuery()
  14. }
  15. override func viewWillDisappear(_ animated: Bool) {
  16. super.viewWillDisappear(animated)
  17. self.listener.remove()
  18. }

从Cloud Firestore实时读取数据

在文档参考就位的情况下,在viewWillAppear(_animated: Bool) ,将您先前创建的侦听器与查询快照的结果相关联,并检索文档列表。 这是通过调用Firestore方法query?.addSnapshotListener :

  1. self.listener = query?.addSnapshotListener { (documents, error) in
  2. guard let snapshot = documents else {
  3. print("Error fetching documents results: \(error!)")
  4. return
  5. }
  6. let results = snapshot.documents.map { (document) -> Task in
  7. if let task = Task(dictionary: document.data(), id: document.documentID) {
  8. return task
  9. } else {
  10. fatalError("Unable to initialize type \(Task.self) with dictionary \(document.data())")
  11. }
  12. }
  13. self.tasks = results
  14. self.documents = snapshot.documents
  15. self.tableView.reloadData()
  16. }

上述分配封闭件的snapshot.documents通过迭代映射所述阵列和它缠绕到一个新的Task模型实例对象快照中的每个数据项。 因此,仅需几行,您就成功地从云中读取了所有任务并将它们分配给全局tasks   数组。

要显示结果,请填充以下内容 TableView 委托方法:

  1. override func numberOfSections(in tableView: UITableView) -> Int {
  2. return 1
  3. }
  4. override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  5. return tasks.count
  6. }
  7. override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  8. let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
  9. let item = tasks[indexPath.row]
  10. cell.textLabel!.text = item.name
  11. cell.textLabel!.textColor = item.done == false ? UIColor.black : UIColor.lightGray
  12. return cell
  13. }

在这一阶段,构建并运行项目,并且在Simulator中您应该能够观察实时出现的数据。 通过Firebase控制台添加数据,您应该看到它立即出现在应用程序模拟器中。

数据出现在应用模拟器中

创建,更新和删除数据

从后端成功读取内容后,接下来,您将创建,更新和删除数据。 下一个示例将使用一个人为设计的示例来说明如何更新数据,在该示例中,该应用仅允许您通过点击单元格将项目标记为完成。 请注意collection.document( item.id ).updateData(["done": !item.done])关闭属性,该属性仅引用特定的文档ID,从而更新字典中的每个字段:

  1. override func tableView(_ tableView: UITableView,
  2. didSelectRowAt indexPath: IndexPath) {
  3. let item = tasks[indexPath.row]
  4. let collection = Firestore.firestore().collection("Tasks")
  5. collection.document(item.id).updateData([
  6. "done": !item.done,
  7. ]) { err in
  8. if let err = err {
  9. print("Error updating document: \(err)")
  10. } else {
  11. print("Document successfully updated")
  12. }
  13. }
  14. tableView.reloadRows(at: [indexPath], with: .automatic)
  15. }

要删除项目,请调用document( item.id ).delete()方法:

  1. override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
  2. return true
  3. }
  4. override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
  5. if (editingStyle == .delete){
  6. let item = tasks[indexPath.row]
  7. _ = Firestore.firestore().collection("Tasks").document(item.id).delete()
  8. }
  9. }

创建一个新任务将涉及在情节提要中添加一个新按钮,并将其IBAction连接到视图控制器,并创建一个addTask(_ sender:)方法。 当用户按下按钮时,它将弹出一个警报表,用户可以在其中添加新的任务名称:

  1. collection("Tasks").addDocument
  2. (data: ["name": textFieldReminder.text ??
  3. "empty task", "done": false])

输入以下内容,完成应用程序的后一部分:

  1. @IBAction func addTask(_ sender: Any) {
  2. let alertVC : UIAlertController = UIAlertController(title: "New Task", message: "What do you want to remember?", preferredStyle: .alert)
  3. alertVC.addTextField { (UITextField) in
  4. }
  5. let cancelAction = UIAlertAction.init(title: "Cancel", style: .destructive, handler: nil)
  6. alertVC.addAction(cancelAction)
  7. //Alert action closure
  8. let addAction = UIAlertAction.init(title: "Add", style: .default) { (UIAlertAction) -> Void in
  9. let textFieldReminder = (alertVC.textFields?.first)! as UITextField
  10. let db = Firestore.firestore()
  11. var docRef: DocumentReference? = nil
  12. docRef = db.collection("Tasks").addDocument(data: [
  13. "name": textFieldReminder.text ?? "empty task",
  14. "done": false
  15. ]) { err in
  16. if let err = err {
  17. print("Error adding document: \(err)")
  18. } else {
  19. print("Document added with ID: \(docRef!.documentID)")
  20. }
  21. }
  22. }
  23. alertVC.addAction(addAction)
  24. present(alertVC, animated: true, completion: nil)
  25. }

再次构建并运行该应用程序,并在出现模拟器时尝试添加一些任务,以及将一些任务标记为已完成,后通过删除一些任务来测试删除功能。 您可以通过切换到Firebase数据库控制台并观察集合和文档来确认已实时更新存储的数据。

控制台中的集合和文档

筛选和复合查询

到目前为止,您仅使用简单的查询,而没有任何特定的过滤功能。 要创建更健壮的查询,可以使用whereField子句按特定值进行过滤:

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

您可以通过使用order(by: )limit(to: ) :)方法limit(to: )对查询数据进行order(by: )limit(to: ) ,如下所示:

docRef.order(by: "name").limit(5)

在FirebaseDo应用程序中,您已经在基本查询中使用了limit 。 在上面的代码片段中,您还利用了复合查询的另一个功能,即顺序和限制都链接在一起。 您可以根据需要链接任意数量的查询,例如以下示例:

  1. docRef
  2. .whereField(“name”, isEqualTo: searchString)
  3. .whereField(“done”, isEqualTo: false)
  4. .order(by: "name")
  5. .limit(5)

结论

在本教程中,您探索了Google的新MBaaS产品Cloud Firestore ,并在此过程中创建了一个简单的任务提醒应用程序,该应用程序演示了在云中持久,同步和查询数据的难易程度。 您了解了与Firebase实时数据库相比Firestore的数据架构结构,以及如何实时读写数据以及更新和删除数据。 您还学习了如何执行简单查询以及复合查询,以及如何过滤数据。

创建Cloud Firestore的目的是提供Firebase实时数据库的鲁棒性,而没有移动开发人员必须忍受的许多限制,尤其是在可伸缩性和查询方面。 我们只是从头开始了解Firestore可以完成的工作,因此当然值得探索一些更的概念,例如使用查询游标对数据进行分页 , 管理索引保护数据 。

翻译自: https://code.tutsplus.com/tutorials/getting-started-with-cloud-firestore-for-ios--cms-30910

分享好友

分享这个小栈给你的朋友们,一起进步吧。

Cloud Firestore
创建时间:2022-04-08 15:52:09
Cloud Firestore
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

技术专家

查看更多
  • LCR_
    专家
戳我,来吐槽~