讀取 Cloud Firestore 的 database

官方文件

新版做法: 利用 FirebaseFirestoreSwift

以下是舊版做法。

import FirebaseFirestore

加入 framework FirebaseFirestore 才能使用 FirebaseFirestore 的相關功能。

範例 1

以 getDocuments 讀取某個 collection 下全部的 documents

collection() 裡可傳入 collection 的名字,因此我們用 db.collection("songs") 取得 songs collection,然後再呼叫 function getDocuments 取得它底下所有的 documents。 (記得要 import Firebase)

let db = Firestore.firestore()db.collection("songs").getDocuments { querySnapshot, error in   if let querySnapshot = querySnapshot {      for document in querySnapshot.documents {         print(document.data())      }   }}

document 的型別為 QueryDocumentSnapshot,利用它的 data() 可取得 dictionary 型別的資料。

比方以下寫法可取得歌名。

let name = document.data()["name"]

結果

["singer": 薛之謙, "rate": 3, "name": 演員]["singer": 田馥甄, "name": 小幸運, "rate": 4]["singer": 周興哲, "name": 你好不好, "rate": 5]

ps: 當 getDocuments 找不到任何 document 時,可利用 querySnapshot.documents.count 是否為 0 判斷。

以 order(by:) 排序,由小到大。

以 rate 排序,由小到大。

let db = Firestore.firestore()db.collection("songs").order(by: "rate").getDocuments { querySnapshot, error in   if let querySnapshot = querySnapshot {      for document in querySnapshot.documents {         print(document.data())      }   }}

結果

["name": 演員, "singer": 薛之謙, "rate": 3]["rate": 4, "singer": 田馥甄, "name": 小幸運]["rate": 5, "singer": 周興哲, "name": 你好不好]

以多個欄位排序,比方先比身高,身高一樣再比體重。

let db = Firestore.firestore()db.collection("students").order(by: "height").order(by: "weight").getDocuments { querySnapshot, error in}

以 order 的參數 descending 為 true 控制排序由大到小。

以 rate 排序,由大到小。

let db = Firestore.firestore()db.collection("songs").order(by: "rate", descending: true).getDocuments { querySnapshot, error in   if let querySnapshot = querySnapshot {      for document in querySnapshot.documents {         print(document.data())      }   }}

結果

["name": 你好不好, "rate": 5, "singer": 周興哲]["singer": 田馥甄, "name": 小幸運, "rate": 4]["singer": 薛之謙, "name": 演員, "rate": 3]

以 limit(to:) 指定抓取的數量。

db.collection("songs").order(by: "rate").limit(to: 2).getDocuments { querySnapshot, error in   if let querySnapshot = querySnapshot {      for document in querySnapshot.documents {         print(document.data())      }   }}

結果

["name": 演員, "rate": 3, "singer": 薛之謙]["name": 小幸運, "singer": 田馥甄, "rate": 4]

利用 whereField 設定 search 的條件。

let db = Firestore.firestore()db.collection("songs").whereField("singer", isEqualTo: "周興哲").getDocuments { querySnapshot, error in   if let querySnapshot = querySnapshot {       for document in querySnapshot.documents {         print(document.data())      }   }}

結果

["name": 你好不好, "singer": 周興哲, "rate": 5]

範例 2

讀取某個 document

let db = Firestore.firestore()db.collection("music").document("周杰倫").getDocument { (document, error) in   if let document = document, document.exists {      print(document.documentID, document.data())   } else {      print("Document does not exist")   }}

結果

周杰倫 Optional(["gender": 男])

讀取某個 document 下的 collection

let db = Firestore.firestore()db.collection("music").document("周杰倫").collection("albums").getDocuments { querySnapshot, error in   if let querySnapshot = querySnapshot {      for document in querySnapshot.documents {         print(document.documentID)      }   }}

結果

葉惠美

利用 document 或 collection 路徑讀取

利用 collection 路徑讀取 documents

let db = Firestore.firestore()db.collection("music/周杰倫/albums").getDocuments { querySnapshot, error in   if let querySnapshot = querySnapshot {      for document in querySnapshot.documents {         print(document.documentID)      }   }}

結果

葉惠美

利用 document 路徑讀取 document

let db = Firestore.firestore()db.document("music/周杰倫").getDocument  { (document, error) in   if let document = document, document.exists {      print(document.documentID, document.data())   } else {      print("Document does not exist")   }}

結果

周杰倫 Optional(["gender": 男])

持續偵測 collection 下的 document 是否有新增,刪除,修改

一開始 addSnapshotListener 會先抓到 collection 下所有的 document, 因此 documentChanges 將包含所有的 document,type 則為 .added。之後 addSnapshotListener 的 closure 再被觸發時,documentChanges 將只包含新增,刪除(removed)或修改(modified)的 document。

let db = Firestore.firestore()db.collection("songs").addSnapshotListener { (querySnapshot, error) in   guard let querySnapshot = querySnapshot else {      return   }   querySnapshot.documentChanges.forEach({ (documentChange) in      if documentChange.type == .added {         print(documentChange.document.data())      }   })}

將偵測到的資料儲存到 array,顯示在表格上

class SongsTableViewController: UITableViewController {

var songs = [QueryDocumentSnapshot]()
override func viewDidLoad() {
super.viewDidLoad()
let db = Firestore.firestore()
db.collection("songs").order(by: "rate").addSnapshotListener { (querySnapshot, error) in
guard let querySnapshot = querySnapshot else {
return
}

self.songs = querySnapshot.documents
self.tableView.reloadData()
}
}

自訂型別儲存 Firebase 抓取的資料

  • 比較方便的方法:

利用 FirebaseFirestoreSwift 將 Firestore 的資料變成自訂型別

  • 其它方法

範例

struct Song {
var name: String
var singer: String
var rate: Int
var youtube: URL?
}
extension Song {
init(dic: [String: Any]) {
name = dic["name"] as? String ?? "街角的祝福"
singer = dic["singer"] as? String ?? "peter pan"
rate = dic["rate"] as? Int ?? 1
if let urlString = dic["youtube"] as? String {
youtube = URL(string: urlString)
}
}
}
class SongsTableViewController: UITableViewController {    var songs = [Song]()

在 SongsTableViewController 裡定義 function getSongs。

方法一: 用 map 將 Firebase 的資料轉換成自訂型別。

func getSongs() {
let db = Firestore.firestore()
db.collection("songs").order(by: "rate").addSnapshotListener { (querySnapshot, error) in
guard let querySnapshot = querySnapshot else {
return
}

self.songs = querySnapshot.documents.map {
Song(dic: $0.data())
}


self.tableView.reloadData()
}
}

方法二: 用 forEach 將 Firebase 的資料轉換成自訂型別。

querySnapshot.documents.forEach { (songDoc) in
let song = Song(dic: songDoc.data())
self.songs.append(song)
}

方法三: 用 for in 將 Firebase 的資料轉換成自訂型別。

for songDoc in querySnapshot.documents {
let song = Song(dic: songDoc.data())
self.songs.append(song)
}

分頁功能

--

--

彼得潘的 iOS App Neverland
彼得潘的 Swift iOS App 開發問題解答集

彼得潘的iOS App程式設計入門,文組生的iOS App程式設計入門講師,彼得潘的 Swift 程式設計入門,App程式設計入門作者,http://apppeterpan.strikingly.com