sql >> Databáze >  >> RDS >> Database

Začínáme s Cloud Firestore pro iOS

Mobilní kodéři již mnoho let využívají platformu Firebase Realtime Database od společnosti Google Mobile Backend as a Service (MBaaS), která jim pomáhá soustředit se na vytváření funkcí pro jejich aplikace, aniž by se museli starat o back-endovou infrastrukturu a databázi. Tím, že Firebase usnadňuje ukládání a uchovávání dat v cloudu a stará se o ověřování a zabezpečení, umožňuje kodérům soustředit se na stranu klienta.

Minulý rok Google oznámil další back-end databázové řešení, Cloud Firestore, postavené od základů s příslibem větší škálovatelnosti a intuitivnosti. To však způsobilo určitý zmatek, pokud jde o jeho místo ve vztahu k již existující vlajkové lodi společnosti Google, Firebase Realtime Database. Tento tutoriál nastíní rozdíly mezi těmito dvěma platformami a výrazné výhody každé z nich. Vytvořením jednoduché aplikace pro připomenutí se naučíte pracovat s referencemi dokumentů Firestore a také číst, zapisovat, aktualizovat a mazat data v reálném čase.

Cíle tohoto kurzu

Tento výukový program vás seznámí s Cloud Firestore. Dozvíte se, jak využít platformu pro perzistenci a synchronizaci databáze v reálném čase. Budeme se zabývat následujícími tématy:

  • co je Cloud Firestore
  • datový model Firestore
  • nastavení Cloud Firestore
  • vytváření referencí Cloud Firestore a práce s nimi
  • čtení dat v reálném čase z Cloud Firestore
  • vytváření, aktualizace a mazání dat
  • filtrování a složené dotazy

Předpokládané znalosti

Tento tutoriál předpokládá, že jste měli určitou zkušenost s Firebase a máte zkušenosti s vývojem pomocí Swift a Xcode.

Co je Cloud Firestore?

Stejně jako Firebase Realtime Database i Firestore poskytuje mobilním a webovým vývojářům cloudové řešení pro více platforem pro uchování dat v reálném čase, bez ohledu na latenci sítě nebo připojení k internetu, a také bezproblémovou integraci se sadou produktů Google Cloud Platform. Spolu s těmito podobnostmi existují výrazné výhody a nevýhody, které jeden od druhého odlišují.

Datový model

Na základní úrovni Realtime Database ukládá data jako jeden velký, monolitický, hierarchický strom JSON, zatímco Firestore organizuje data v dokumentech a kolekcích a také v podsbírkách. To vyžaduje méně denormalizace. Ukládání dat do jednoho stromu JSON má výhody jednoduchosti, pokud jde o práci s jednoduchými požadavky na data; při práci se složitějšími hierarchickými daty se však ve velkém měřítku stává těžkopádnější.

Podpora offline

Oba produkty nabízejí offline podporu, aktivně ukládají data do mezipaměti ve frontách, když existuje latentní nebo žádné síťové připojení – synchronizace místních změn zpět do back-endu, je-li to možné. Firestore podporuje offline synchronizaci pro webové aplikace kromě mobilních aplikací, zatímco databáze v reálném čase umožňuje pouze mobilní synchronizaci.

Dotazy a transakce 

Databáze v reálném čase podporuje pouze omezené možnosti třídění a filtrování – v jediném dotazu můžete třídit nebo filtrovat pouze na úrovni vlastností, ale ne obojí. Dotazy jsou také hluboké, což znamená, že vracejí zpět velký podstrom výsledků. Produkt podporuje pouze jednoduché operace zápisu a transakce, které vyžadují zpětné volání dokončení.

Firestore na druhou stranu zavádí indexové dotazy se složeným tříděním a filtrováním, což umožňuje kombinovat akce a vytvářet řetězové filtry a řazení. Můžete také provádět mělké dotazy vracející podsbírky namísto celé kolekce, kterou byste získali s Realtime Database. Transakce jsou atomické povahy, ať už odesíláte dávkovou operaci nebo jednu operaci, přičemž transakce se automaticky opakují, dokud nejsou uzavřeny. Realtime Database navíc podporuje pouze jednotlivé transakce zápisu, zatímco Firestore umožňuje dávkové operace atomicky.

Výkon a škálovatelnost

Databáze v reálném čase, jak byste očekávali, je poměrně robustní a má nízkou latenci. Databáze jsou však omezeny na jednotlivé oblasti v závislosti na zónové dostupnosti. Firestore na druhé straně uchovává data horizontálně napříč více zónami a regiony, aby byla zajištěna skutečná globální dostupnost, škálovatelnost a spolehlivost. Google ve skutečnosti slíbil, že Firestore bude spolehlivější než databáze v reálném čase.

Dalším nedostatkem databáze v reálném čase je omezení na 100 000 souběžných uživatelů (100 000 souběžných připojení a 1 000 zápisů/sekundu v jedné databázi), po kterém byste museli databázi rozdělit (rozdělit databázi do více databází), abyste mohli podporovat více uživatelů. . Firestore se automaticky škáluje napříč více instancemi, aniž byste museli zasahovat.

Firestore, navržený od základů s ohledem na škálovatelnost, má novou schematickou architekturu, která replikuje data ve více oblastech, stará se o autentizaci a zpracovává další záležitosti související se zabezpečením, to vše v rámci sady SDK na straně klienta. Jeho nový datový model je intuitivnější než Firebase, více se podobá jiným srovnatelným NoSQL databázovým řešením, jako je MongoDB, a zároveň poskytuje robustnější dotazovací modul.

Zabezpečení 

A konečně, databáze v reálném čase, jak víte z našich předchozích tutoriálů, spravuje zabezpečení pomocí kaskádových pravidel se samostatnými spouštěči ověřování. Funguje to s pravidly databáze Firebase, která ověřují vaše data samostatně. Firestore na druhé straně poskytuje jednodušší, ale výkonnější model zabezpečení využívající pravidla zabezpečení Cloud Firestore a správu identity a přístupu (IAM), s automatickou výjimkou ověřování dat.

  • Mobile DevelopmentFirebase Security RulesChike Mgbemena

Datový model Firestore

Firestore je databáze založená na NoSQL dokumentech, sestávající z kolekcí dokumentů, z nichž každý obsahuje data. Jelikož se jedná o NoSQL databázi, nezískáte tabulky, řádky a další prvky, které byste našli v relační databázi, ale místo toho sady párů klíč/hodnota, které byste našli v dokumentech.

Dokumenty a kolekce vytváříte implicitně přiřazením dat k dokumentu, a pokud dokument nebo kolekce neexistuje, bude automaticky vytvořena za vás, protože kolekce musí být vždy kořenovým (prvním) uzlem. Zde je jednoduché schéma příkladu Tasks projektu, na kterém budete brzy pracovat, sestávající z kolekce Tasks a také mnoha dokumentů obsahujících dvě pole, název (řetězec) a příznak, zda je úkol dokončen (boolean) .

Pojďme si každý z prvků rozložit, abyste jim lépe porozuměli.

Sbírky

Kolekce, které jsou synonymem pro databázové tabulky ve světě SQL, obsahují jeden nebo více dokumentů. Kolekce musí být kořenovými prvky vašeho schématu a mohou obsahovat pouze dokumenty, nikoli jiné kolekce. Můžete však odkazovat na dokument, který zase odkazuje na sbírky (podsbírky).

Ve výše uvedeném diagramu se úkol skládá ze dvou primitivních polí (jméno a hotovo) a také z podsbírky (dílčího úkolu), která se skládá ze dvou vlastních primitivních polí.

Dokumenty

Dokumenty se skládají z párů klíč/hodnota, přičemž hodnoty mají jeden z následujících typů: 

  • primitivní pole (jako jsou řetězce, čísla, logická hodnota)
  • složité vnořené objekty (seznamy nebo pole primitiv)
  • podsbírky

Vnořené objekty se také nazývají mapy a mohou být v dokumentu znázorněny následovně. Následuje příklad vnořeného objektu a pole:

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

Další informace o podporovaných typech dat naleznete v dokumentaci k datovým typům společnosti Google. Dále nastavíte projekt pro práci s Cloud Firestore.

Nastavení projektu

Pokud jste již dříve pracovali s Firebase, mnoho z toho by vám mělo být známé. V opačném případě si budete muset vytvořit účet ve Firebase a postupovat podle pokynů v části „Nastavit projekt“ v našem předchozím kurzu Začínáme s ověřováním Firebase pro iOS .

Chcete-li pokračovat v tomto výukovém programu, naklonujte repo projektu výukového programu. Dále zahrňte knihovnu Firestore od přidání následujícího do vašeho Podsouboru :

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

Pro vytvoření knihovny zadejte do svého terminálu následující:

pod install

Dále přepněte na Xcode a otevřete  .xcworkspace soubor. Přejděte na AppDelegate.swift  a do pole application:didFinishLaunchingWithOptions: zadejte následující metoda:

FirebaseApp.configure()

V prohlížeči přejděte do konzole Firebase a vyberte Databáze kartu vlevo.

Ujistěte se, že jste vybrali možnost Spustit v testovacím režimu abyste během experimentování neměli žádné problémy se zabezpečením a při přesunu aplikace do produkce dbejte na bezpečnostní upozornění. Nyní jste připraveni vytvořit kolekci a několik vzorových dokumentů.

Přidání sbírky a vzorového dokumentu

Chcete-li začít, vytvořte úvodní kolekci Tasks , výběrem možnosti Přidat sbírku a pojmenování kolekce, jak je znázorněno níže:

U prvního dokumentu necháte ID dokumentu prázdné, čímž se ID automaticky vygeneruje za vás. Dokument se bude jednoduše skládat ze dvou polí: namedone .

Uložte dokument a měli byste být schopni potvrdit sbírku a dokument spolu s automaticky vygenerovaným ID:

S databází nastavenou pomocí vzorového dokumentu v cloudu jste připraveni začít implementovat Firestore SDK v Xcode.

Vytvoření a práce s databázovými referencemi

Otevřete soubor MasterViewController.swift soubor v Xcode a přidejte následující řádky pro import knihovny:

import Firebase

class MasterViewController: UITableViewController {
    @IBOutlet weak var addButton: UIBarButtonItem!
    
    private var documents: [DocumentSnapshot] = []
    public var tasks: [Task] = []
    private var listener : ListenerRegistration!
   ...

Zde jednoduše vytváříte proměnnou posluchače, která vám umožní spustit připojení k databázi v reálném čase, když dojde ke změně. Vytváříte také DocumentSnapshot odkaz, který bude obsahovat dočasný snímek dat.

Než budete pokračovat s ovladačem zobrazení, vytvořte další soubor swift, Task.swift , který bude reprezentovat váš datový model:

import Foundation

struct Task{
    var name:String
    var done: Bool
    var id: String
    
    var dictionary: [String: Any] {
        return [
            "name": name,
            "done": done
        ]
    }
}

extension Task{
    init?(dictionary: [String : Any], id: String) {
        guard   let name = dictionary["name"] as? String,
            let done = dictionary["done"] as? Bool
            else { return nil }
        
        self.init(name: name, done: done, id: id)
    }
}

Výše uvedený fragment kódu obsahuje vlastnost pohodlí (slovník) a metodu (init), které usnadní naplnění objektu modelu. Přepněte zpět na řadič pohledu a deklarujte proměnnou globálního nastavení, která omezí základní dotaz na 50 nejlepších položek v seznamu úkolů. Jakmile nastavíte proměnnou dotazu, odeberete také posluchač, jak je uvedeno v didSet vlastnost níže:

fileprivate func baseQuery() -> Query {
        return Firestore.firestore().collection("Tasks").limit(to: 50)
    }
    
    fileprivate var query: Query? {
        didSet {
            if let listener = listener {
                listener.remove()
            }
        }
    }

override func viewDidLoad() {
        super.viewDidLoad()
        self.query = baseQuery()
    }

 override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        self.listener.remove()
    }

Čtení dat v reálném čase z Cloud Firestore

S odkazem na dokument v viewWillAppear(_animated: Bool) , přiřaďte dříve vytvořený posluchač k výsledkům snímku dotazu a načtěte seznam dokumentů. To se provádí voláním metody Firestore query?.addSnapshotListener :

self.listener =  query?.addSnapshotListener { (documents, error) in
            guard let snapshot = documents else {
                print("Error fetching documents results: \(error!)")
                return
            }
            
            let results = snapshot.documents.map { (document) -> Task in
                if let task = Task(dictionary: document.data(), id: document.documentID) {
                    return task
                } else {
                    fatalError("Unable to initialize type \(Task.self) with dictionary \(document.data())")
                }
            }
            
            self.tasks = results
            self.documents = snapshot.documents
            self.tableView.reloadData()
            
        }

Výše uvedený uzávěr přiřazuje snapshot.documents iterativním mapováním pole a jeho zabalením do nového Task objekt instance modelu pro každou datovou položku ve snímku. Takže pomocí několika řádků jste úspěšně načetli všechny úkoly z cloudu a přiřadili je ke globálním tasks   pole.

Chcete-li zobrazit výsledky, vyplňte následující TableView delegovat metody:

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

V této fázi sestavte a spusťte projekt a v simulátoru byste měli být schopni sledovat data objevující se v reálném čase. Přidejte data prostřednictvím konzole Firebase a měli byste je okamžitě vidět v simulátoru aplikace.

Vytváření, aktualizace a mazání dat

Po úspěšném načtení obsahu z back-endu dále vytvoříte, aktualizujete a odstraníte data. Následující příklad bude ilustrovat, jak aktualizovat data, pomocí vymyšleného příkladu, kdy vám aplikace umožní označit položku jako hotovou pouze klepnutím na buňku. Všimněte si collection.document( item.id ).updateData(["done": !item.done]) vlastnost uzavření, která jednoduše odkazuje na konkrétní ID dokumentu a aktualizuje každé z polí ve slovníku:

override func tableView(_ tableView: UITableView,
                            didSelectRowAt indexPath: IndexPath) {

        let item = tasks[indexPath.row]
        let collection = Firestore.firestore().collection("Tasks")

        collection.document(item.id).updateData([
            "done": !item.done,
            ]) { err in
                if let err = err {
                    print("Error updating document: \(err)")
                } else {
                    print("Document successfully updated")
                }
        }

        tableView.reloadRows(at: [indexPath], with: .automatic)
        
    }

Chcete-li odstranit položku, zavolejte document( item.id ).delete() metoda:

override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        return true
    }
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {

        if (editingStyle == .delete){
            let item = tasks[indexPath.row]
            _ = Firestore.firestore().collection("Tasks").document(item.id).delete()
        }

    }

Vytvoření nového úkolu bude zahrnovat přidání nového tlačítka do Storyboardu a připojení jeho IBAction k řadiči zobrazení a vytvoření addTask(_ sender:) metoda. Když uživatel stiskne tlačítko, zobrazí se list s upozorněním, kde může uživatel přidat nový název úkolu:

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

Dokončete poslední část aplikace zadáním následujícího:

@IBAction func addTask(_ sender: Any) {
        
        let alertVC : UIAlertController = UIAlertController(title: "New Task", message: "What do you want to remember?", preferredStyle: .alert)
        
        alertVC.addTextField { (UITextField) in
            
        }
        
        let cancelAction = UIAlertAction.init(title: "Cancel", style: .destructive, handler: nil)
        
        alertVC.addAction(cancelAction)
        
        //Alert action closure
        let addAction = UIAlertAction.init(title: "Add", style: .default) { (UIAlertAction) -> Void in
            
            let textFieldReminder = (alertVC.textFields?.first)! as UITextField
            
            let db = Firestore.firestore()
            var docRef: DocumentReference? = nil
            docRef = db.collection("Tasks").addDocument(data: [
                "name": textFieldReminder.text ?? "empty task",
                "done": false
            ]) { err in
                if let err = err {
                    print("Error adding document: \(err)")
                } else {
                    print("Document added with ID: \(docRef!.documentID)")
                }
            }
            
        }
    
        alertVC.addAction(addAction)
        present(alertVC, animated: true, completion: nil)
        
    }

Sestavte a spusťte aplikaci ještě jednou, a když se objeví simulátor, zkuste přidat několik úkolů a také některé označit jako dokončené a nakonec otestujte funkci odstranění odstraněním některých úkolů. Chcete-li potvrdit, že uložená data byla aktualizována v reálném čase, přepněte se do své databáze Firebase a sledujte sbírku a dokumenty.

Filtrování a složené dotazy

Doposud jste pracovali pouze s jednoduchým dotazem, bez jakýchkoli specifických možností filtrování. Chcete-li vytvořit o něco robustnější dotazy, můžete filtrovat podle konkrétních hodnot pomocí whereField klauzule:

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

Data dotazu si můžete objednat a omezit pomocí order(by: ) a limit(to: ) způsoby takto:

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

V aplikaci FirebaseDo jste již využili limit se základním dotazem. Ve výše uvedeném úryvku jste také využili další funkci, složené dotazy, kde jsou příkaz i limit zřetězeny dohromady. Můžete řetězit tolik dotazů, kolik chcete, jako v následujícím příkladu:

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

  1. Jak převést řetězec na číselnou hodnotu v PostgreSQL

  2. SQL Server Express Backup Database | Jak naplánovat automatizaci a vyčištění SQL Express Backup

  3. Vývoj modulu s Java 9 v Eclipse IDE, část 2

  4. Jak najít formát data používaný v aktuální relaci v SQL Server (T-SQL)