讀取 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)
}