【Firebase】它要怎麼排序呢?(補充)
在上集的庫存APP中,雖然把東西做出來了,但熊熊發現我明明就有寫排序的Code呀,卻完全沒有反應,排序在資料庫中是很正常的功能吧?不然要資料庫幹嘛呢?如果利用手機小小的CPU去排序,一下子就沒電了呀,我想我的人品應該沒有問題吧?所以就去問問高高手同事,也查了一下,發現…果然是我的問題呀…XD,現在我們就來排序吧。
排序
測試資料
- 就一個很簡單的書籍列表,資料都是從博客來Copy來的,主要要注意的地方是,BarCode是為了測試才使用A~E的值
{
"Books": {
"BarCode": {
"E": {
"ISBN": 9789863843344,
"Title": "世界大局.地圖全解讀",
"URL": "https://www.books.com.tw/products/0010822566",
"Icon": null,
"Count": 0,
"Timestamp": 9789863843344
},
"D": {
"ISBN": 9789578787322,
"Title": "一日三餐減醣料理:單週無壓力消失2kg的美味計劃,72道低醣速瘦搭配餐",
"URL": "https://www.books.com.tw/products/0010789764",
"Icon": null,
"Count": 0,
"Timestamp": 9789863843344
},
"C": {
"ISBN": 9789573285304,
"Title": "表裡不一的動物超棒的!圖鑑 (電子書)",
"URL": "https://www.books.com.tw/products/E050045960",
"Icon": null,
"Count": 0,
"Timestamp": 9789863843344
},
"B": {
"ISBN": 9789571377995,
"Title": "愛對了,每天都是情人節:以「16型愛情氣質」探尋屬於你的美好伴侶",
"URL": "https://www.books.com.tw/products/0010822829",
"Icon": null,
"Count": 0,
"Timestamp": 9789863843344
},
"A": {
"ISBN": 9787111617976,
"Title": "Flutter技術入門與實戰",
"URL": "https://www.books.com.tw/products/CN11615679",
"Icon": null,
"Count": 0,
"Timestamp": 9789863843344
}
}
}
}
排序跟沒排序
- 其實在官方文件是有說明的,但是…寫得實在是有看沒有懂(其實是我的英文太爛了),重點就在下面,不過要注意的是它只會順著由小到大排序,如果要反過來的話,就要在程式內自己去把Array倒過來排了…
datasnapshot.value // 沒有排序的 (DataSnapshot)
datasnapshot.children // 有排過序的 (NSEnumerator)
// MARK: - 小工具
extension ViewController {
/// 產生[book]
private func booksMaker(withChildren children: NSEnumerator) -> [Book] {
var books = [Book]()
for child in children {
if let child = child as? DataSnapshot {
let bookData = child.value as? [String: Any]
if let book = self.bookMaker(withValue: bookData) { books.append(book) }
}
}
return books
}
/// 產生book
private func bookMaker(withValue value: [String: Any]?) -> Book? {
guard let value = value,
let isbn = value["ISBN"] as? Int,
let title = value["Title"] as? String
else {
return nil
}
let book = Book(ISBN: isbn, Title: title)
return book
}
}
排序程式
- 其實就只是把排序的Code加上去而已,另外不得不說,Swift的Enum真的是太好用了,可以加上變數…XD
import UIKit
import FirebaseDatabase
// MARK: - Firebase工具
class FIRDatabase: NSObject {
/// 排序的類型
enum OrderType {
case none
case queryOrderedByKey
case queryOrderedByValue
case queryOrderedByPriority
case queryOrderedByChild(field: Book.Field)
}
public static let shared = FIRDatabase()
private let reference = Database.database().reference()
private override init() { super.init() }
}
// MARK: - 小工具
extension FIRDatabase {
/// 取得資料 (及時)
func childValueForRealtime(withPath path: String, orderType type: OrderType ,result: @escaping (Result<DataSnapshot?, Error>) -> Void) -> UInt? {
let _reference = reference.child(path)
var queryReference: DatabaseQuery?
switch type {
case .none: queryReference = _reference
case .queryOrderedByKey: queryReference = _reference.queryOrderedByKey()
case .queryOrderedByValue: queryReference = _reference.queryOrderedByValue()
case .queryOrderedByPriority: queryReference = _reference.queryOrderedByPriority()
case .queryOrderedByChild(let field): queryReference = _reference.queryOrdered(byChild: field.rawValue)
}
let handleNumber = queryReference?.observe(.value, with: { (snapshot) in
result(.success(snapshot))
}, withCancel: { (error) in
result(.failure(error))
})
return handleNumber
}
}
根據主Key做排序
- 就是queryOrderedByKey() => BarCode (A~E)
// MARK: - 小工具
extension ViewController {
/// 取得書本資料
private func booksForRealtime() {
let path = "Books/BarCode"
_ = FIRDatabase.shared.childValueForRealtime(withPath: path, orderType: .queryOrderedByKey) { (result) in
switch(result) {
case .failure(let error): print(error)
case .success(let snapshot):
guard let snapshot = snapshot else { return }
self.books = self.booksMaker(withChildren: snapshot.children)
self.myTableView.reloadData()
}
}
}
}
根據內容的Key做排序
- 就是queryOrdered(byChild:) => { ISBN: }
// MARK: - 小工具
extension ViewController {
/// 初始化設定
private func initSetting() {
myTableView.delegate = self
myTableView.dataSource = self
}
/// 取得書本資料
private func booksForRealtime() {
let path = "Books/BarCode"
_ = FIRDatabase.shared.childValueForRealtime(withPath: path, orderType: .queryOrderedByChild(field: .ISBN)) { (result) in
switch(result) {
case .failure(let error): print(error)
case .success(let snapshot):
guard let snapshot = snapshot else { return }
self.books = self.booksMaker(withChildren: snapshot.children)
self.myTableView.reloadData()
}
}
}
}
範例程式碼下載
後記
- 其實排序這件事情,我一開始也是把資料傳回來之後,在手機上去做排序,後來想想太笨了,果然是『不經一坑,不長一智』啊。