Get updates on your email

Wednesday, November 7, 2018

Firestore CRUD functionalities

This is possibly the simplest implementation of CRUD functionality of firestore.

Create a collection called user and leave the Document ID and blank add fields, their types and values:


I've a collection named as Users and I'll share how you can first save, retrieve and then update totalGamesPlayed

The visible data in this photo is showing totalGamesPlayed is 40

Before we dive into storing it is important to match that you have the same rules for database as I have:


In you XCode project make sure you have installed the pod for firestore:
pod 'Firebase/Core'
pod 'Firebase/Firestore'

Also I've installed pod 'Firebase/Auth' too as I've implemented login with google on the app that I'm using as an example.

On top import this:

import FirebaseFirestore

Add New Data to Firestore:

let userCollection = Firestore.firestore().collection("Users")
                
                var userObj: [String: Any] {
                    return ["userID": "12345",
                            "email": "my@email.com",
                            "fullName": "Chaudhry Talha",
                            "totalGamesPlayed": totalGamesPlayed ,
                    ]
                }
                

                userCollection.addDocument(data: userObj)

Here the totalGamesPlayed is just an Int that I'll be storing. Doing so will save the data into the database.

Retrieve or Get Data from Firestore:

This has two sub-parts:

  • Get all the users
  • Get users based on a filter

Before we start implementing them there is a common part that both of them will use. This is the basic settings before we start retrieving:

let db: Firestore = Firestore.firestore()
let settings = db.settings
settings.areTimestampsInSnapshotsEnabled = true
db.settings = settings

Get all the users


        db.collection("Users").getDocuments { (snapshot, error) in
            if let err = error {
                print("Error: \(err)")
            } else {
                for document in snapshot!.documents {
                    let totalGPlay = document.get("totalGamesPlayed") as! Int
                        print("Total Game Played: \(totalGPlay)")
                    //print(document.data()) //this is a Dictionary. Uncomment this to get the full retrieved document
                }
            }
        }

Our db is calling the Users collection to perform getDocuments. If there is no error we are running a for loop on all the documents that were retrieved. Then we are storing and printing just totalGamesPlayed. As in first screenshot we have just two entries so it retrieved two documents and printed it successfully.

Get users based on a filter

If you want to filter the getDocuments you have to add a query after the db.settings = settings line.


var query: Query


query = db.collection("Users").whereField("totalGamesPlayed", isEqualTo: 40)

The best scenerio would be to add this filter on a unique field like email to get all the entries for that specific email address.

query.getDocuments { (snapshot, error) in
            if let err = error {
                print("Error:  \(err)")
            } else {
                for document in snapshot!.documents {
                    let totalGPlay = document.get("totalGamesPlayed") as! Int
                    print("Ttal Game Played: \(totalGPlay)")
                    //print(document.data()) //uncomment to print the full document
                }
            }

        }

This is same as getting all users but here instead of applying getDocuments function on all the database (db) collection we are just applying it on a query and this just gave us one document as there is only entry where total games played is 40.

Update a specific Document

There can be number of ways to update a record but the one I choose is serving the purpose of my project i.e. Get user based on a filter (which will be always one) and then get the unique autoID (Document ID) and update that record.

var query: Query

        query = db.collection("Users").whereField("email", isEqualTo: "my@gmail.com")

Same thing but changed the query to get user by a specific email.

query.getDocuments { (snapshot, error) in
            if let err = error {
                print("Error: \(err)")
            } else {
                    
                    let docID = snapshot!.documents.first?.documentID
                    db.collection("Users").document(docID!).setData([ "totalGamesPlayed": 333 ], merge: true)
                
            }

        }

get document based on the query and if there is no error get the documentID for the first document in snapshot documents. Finally go to Users collection where document id is docID and setData (which means change data) of key total games played to 333.

This will successfully update your record by overwriting.


CRUD Core Data Example

Make a new project and you don't need to check core data for now we will tell you another way to add a data file.


Here is an example:

We will have two entities. First one is user and the other one is called as cars. It'll be a one to many relationship, which means a user can have multiple cars but a car will have one user.

Or another example would a game log. Which means a user can play multiple game but a game will be played by only one user. So this is a one to many relationship.

Go ahead and add a new file and select DataModel name is and save it in the project.


Add entities and attributes, give types to attributes and make relationships.

In your AppDelegate.swift after var window: UIWindow? add this code:

lazy var persistentContainer: NSPersistentContainer = {
        
        let container = NSPersistentContainer(name: "NameOfDataModel")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error {
                
                fatalError("Unresolved error, \((error as NSError).userInfo)")
            }
        })
        return container

    }()

Go to your ViewController.swift and assign this variable:

let appDelegate = UIApplication.shared.delegate as? AppDelegate

Let's create a function where we will check if a use exist or not, if they do exist then add the new game data to their record and if they don't exist then make a new user and then add the game data for them.
_______________________________________________________________
func saveEverything() {
        
        let managedContext = appDelegate?.persistentContainer.viewContext
        let fetchRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "UsersLog")
        fetchRequest.predicate = NSPredicate(format: "email = %@""my@email.com") //this will search the records based on the email
        
        do {
            let fetchUser = try managedContext?.fetch(fetchRequest)
             //if fetchuser found something it's count will be greater than one
            if (fetchUser?.count ?? 0 > 0) {
                //picking up the first result
                let foundedUserLog = fetchUser?[0] as! NSManagedObject
                
                foundedUserLog.setValue(user?.email, forKey: "email")
                foundedUserLog.setValue(user?.displayName, forKey: "fullName")
                
//creating a new game log entity for the found user
                let gameLogEntity = NSEntityDescription.entity(forEntityName: "GameLog", in: managedContext!)! 
//creating a new object to add game data
                let gameLog = NSManagedObject(entity: gameLogEntity, insertInto: managedContext)
                let date = Date()
                
                gameLog.setValue(date, forKey: "logEntryDate")
                gameLog.setValue(finalScore, forKey: "finalScore")
                //This is the only line that is different. Here we are giving the founded user
                gameLog.setValue(foundedUserLog, forKey: "userID")
                
//saving data
                do {
                    try managedContext?.save()
                } catch {
                    print(error)
                }
                
            } else {

//create a new entity and object for user
                let userEntity = NSEntityDescription.entity(forEntityName: "UsersLog", in: managedContext!)!
                let newUserLog = NSManagedObject(entity: userEntity, insertInto: managedContext)
                
               
                newUserLog.setValue(user?.email, forKey: "email")
                newUserLog.setValue(user?.displayName, forKey: "fullName")
                
                let gameLogEntity = NSEntityDescription.entity(forEntityName: "GameLog", in: managedContext!)!
                let gameLog = NSManagedObject(entity: gameLogEntity, insertInto: managedContext)
                let date = Date()
                
                gameLog.setValue(date, forKey: "logEntryDate")
                gameLog.setValue(finalScore, forKey: "finalScore")
                gameLog.setValue(newUserLog, forKey: "userID")
                
                do {
                    try managedContext?.save()
                } catch {
                    print(error, error.localizedDescription)
                }
                
            }
        } catch {
            print(error)
        }

    }

_______________________________________________________________

Now that you have saved the data here is how you can retrieve it:
Go to your scoreboardViewController.swift and make a new variable

let appDelegate = UIApplication.shared.delegate as? AppDelegate

func retriveUserData() {
        let managedContext = appDelegate?.persistentContainer.viewContext
        let userFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "UsersLog")
        userFetchRequest.predicate = NSPredicate(format: "email = %@""my@email.com")
        
        do {
            let fetchUser = try managedContext?.fetch(userFetchRequest)
            if (fetchUser?.count ?? 0 > 0) {
                let foundedUser: UsersLog = fetchUser?.first as! UsersLog
                let userGames = foundedUser.game?.allObjects as! [GameLog] //you can loop to get data from all the games
                tempTextView.text = "Name: \(foundedUser.fullName ?? "Name not Found") has played \(userGames.count) games"
                
            } else {
                tempTextView.text = "This user haven't played any games yet."
            }
        } catch {
            print(error)
        }


    }

Other than that here are the basic crud functions:








Tuesday, July 24, 2018

Macho error while installing pods

A method that worked for me is removing the current version or versions:
gem uninstall ruby-macho
And then reinstalling it again with:
gem install ruby-macho --source=http://rubygems.org

Tuesday, October 10, 2017

Custom Marker Snippet for Google Map Using Swift 4

Before moving you need to implement google map on a view controller. Which you can find anywhere easily. This tutorial will tell you how you can add a marker and when you tap on that market it will display a custom snippet with button and label.

Friday, September 15, 2017

Getting Started on Firebase for iOS | Beginner's Tutorial

In this tutorial we will develop an iOS app which will use Firebase as a backend. The app is called GroceryBit and it's a simple app where a wife can add grocery items to the list of her husband and he can view them on his phone.

Thursday, August 3, 2017

Tuesday, June 27, 2017

Implementing UISearch in Collection View with swift

In this tutorial we will implement UiCollectionView and add a UISearchBar on it using swift 3.