How to Read/Write from One iOS App Set Up with Firebase, to Another Firebase Database Contained in Another Firebase Project? Swift 3

How to read/write from one IOS App set up with firebase, to another firebase database contained in another firebase project? Swift 3

Responding the question and comments.

As you know, when a user registers with Firebase, a user account is created on the Firebase server and the user is provided a user id (uid).

A typical design pattern is to have a /users node in Firebase that stores other information about the user, such as a nickname, address or phone number.

We can leverage that /users node to also indicate what kind of user it is; Worker or Client, which would tie into the rest of the app and Firebase so they get to the correct data.

For example

users
uid_0
nickname: "John"
user_type: "Worker"
uid_1
nickname: "Paul"
user_type: "Client"
uid_2
nickname: "George"
user_type: "Worker"
uid_3
nickname: "Ringo"
user_type: "Worker"

As you can see, John, George and Ringo are all workers and Paul is a client.

When the user logs in, the Firebase signIn function will return the users auth data, which contains the uid.

    Auth.auth().signIn(withEmail: "paul@harddaysnight.com", password: "dog",
completion: { (auth, error) in

if error != nil {
let err = error?.localizedDescription
print(err!)
} else {
print(auth!.uid)
//with the uid, we now lookup their user type from the
//users node, which tells the app if they are a client
//or worker
}
})

If the app data is divided like this

app
client_data
...
worker_data
...

A simple rule could be set up that verifies the users user_type is Worker for the worker_data node and Client for the client_data node. Here's a pseudo example that will allow a Client user to only access the data in the client_data node (conceptual)

rules 
client_data
$user_id
".read": "auth != null && root.child(users)
.child($user_id)
.child("user_type") == 'Client'"

Retrieving data from Firebase and using it in another Firebase database reference

A couple of things:

Firebase is Asynchronous and you have to account for that in your code. As it is in the post, the second Firebase function may execute before the first Firebase function has successfully returned data i.e. restaurantName may be nil when the second call happens.

You should nest your calls (in this use case) to ensure data is valid before working with it. Like this.. and keep reading

let ownersRef = rootRef.child("owners")
let restaurantRef = rootRef.child("restaurants")

func viewDidLoad() {
fetchOwner("owner uid")
}

func fetchOwner(ownerUid: String) {

var restaurantName: String?

let uid = FIRAuth.auth()?.currentUser?.uid
ownserRef.child(ownerUid).observeSingleEvent(of: .value, with: { snapshot in

if let dict = snapshot.value as? [String: AnyObject] {
restaurantId = dict["restaurant_id"] as? String
fetchRestaurant(restaurantId)
}
}
})
}

func fetchRestaurant(restaurantId: String) {
restaurantRef.child(restaurantId).observeSingleEvent(of: .value, with: { snapshot in

if let dict = snapshot.value as? [String: AnyObject] {
let restaurantName = dict["name"] as! String
let menuDict = dict["menu"] as! [String:Any]
self.dataSourceArray.append(menuDict)
menuTableView.reloadData()
}
}
}

Most importantly, it's almost always best practice to disassociate your key names from the data it contains. In this case, you're using the restaurant name as the key. What if the restaurant name changes or is updated? You can't change a key! The only option is to delete it and re-write it.... and... every node in the database that refers to it.

A better options it to leverage childByAutoId and let Firebase name the nodes for you and keep a child that has the relevant data.

restaurants
-Yii9sjs9s9k9ksd
name: "Bobs Big Burger Barn"
owner: -Y88jsjjdooijisad
menu:
-y8u8jh8jajsd
name: "Belly Buster Burger"
type: "burger"
price: "$1M"
-j8u89joskoko
name: "Black and Blue Burger"
type: "burger"
price: "$9.95"

As you can see, I leveraged childByAutoId to create the key for this restaurant, as well as the items on the menu. I also referenced the owner's uid in the owner node.

In this case, If the Belly Buster Burger changes to the Waist Slimming Burger, we can make one change and it's done and anything that references it is also updated. Same thing with the owner, if the owner changes, then just change the owner uid.

If the restaurant name changes to Tony's Taco Tavern, just change the child node and it's done.

Hope that helps!

edit: Answer to a comment:

To get the string (i.e. the 'key' of a key:value pair) immediately created by .childByAutoId()

    let testRef = ref.child("test").childByAutoId()
let key = testRef.key
print(key)

Use more than one Firebase database in single app - Swift

The proper way to initialize another database is to initialize another app, using the FIROptions constructor, like so:

FIRDatabase().database() // gets you the default database

let options = FIROptions(googleAppID: bundleID: , GCMSenderID: , APIKey: , clientID: , trackingID: , androidClientID: , databaseURL: "https://othernamespace.firebaseio.com", storageBucket: , deepLinkURLScheme: ) // fill in all the other fields
FIRApp.configureWithName("anotherClient", options: options)
let app = FIRApp(named: "anotherClient")
FIRDatabase.database(app: app!) // gets you the named other database

Or you can initialize from another named plist rather than a huge constructor:

let filePath = NSBundle.mainBundle().pathForResource("MyCool-GoogleService-Info", ofType:"plist")
let options = FIROptions(contentsOfFile:filePath)

Pass data from one app to another app using Firebase

This task can be easily accomplished with Firebase. You would need a Rider node and a Driver node.

The rider would post a request to the driver's request node, which would notify the driver. If the driver accepts, that would be posted to the rider node who would be notified.

Each driver would add a Firebase observer to their driver node and each rider would add an observer to their rider node.

Drivers
driver_01
requests:
rider_01: true
rider_02: true

Riders
rider_01
responses
driver_01: false
rider _02
responses
driver_02: true

With the above structure, rider_01 has requested a ride from driver_01, and rider_02 has also requested a ride from driver_01.

driver_01 declined rider_01 request but accepted driver_02 request.

As the exchange occurs, riders and drivers receive events from Firebase which could then trigger a popup window.

iOS Swift Create Child in Firebase Realtime Database Programatically

After you do the FIRAuth.auth()?.createUser, you can check if the error is nil or not. If it is not, then you know the user has been created, and therefore can add your new child. You can do this by writing:

let uid: String = (FIRAuth.auth()?.currentUser?.uid)!
FIRDatabase.database().reference().child(uid).setValue(arrayOfData)

Therefore, the new node that you create is the user's Firebase ID, and will definitely be unique.

iOS: Firebase: Database lives in a different region. Where to put the link?

You have to put that code wherever you are creating a reference to data from Firebase.

If you look at this code from step 3 of the Firebase documentation on setting up a connection to the database:

var ref: DatabaseReference!

ref = Database.database().reference()

This syntax creates a reference to the database as it is defined in your GoogleService-Info.plist file.

Since you want to specify the URL in your code, you'd do:

var ref: DatabaseReference!

ref = Database.database("your database URL").reference()

And then use ref everywhere else to read and write data.


You can alternatively also download an updated GoogleService-Info.plist file from the Firebase console, and replace the one in your Xcode project with it. In that case the SDK will pick up the URL from the updated file.



Related Topics



Leave a reply



Submit