New Firebase - Cannot query data. What is the new syntax? - ios

I am trying to move to the new Firebase from the old one (launched today, May 18th, 2016), but the query syntax is unclear to me. The only example I can find to make a query is via a listener.
I've followed the docs (https://firebase.google.com/docs/database/ios/retrieve-data), but they are very unclear as to how to simply query one piece of data in the Firebase realtime DB.
The old docs were fine, but the new ones are terrible, imo. Also, their examples on github, where I got some of the code I'm now trying to use, are overly complex (https://github.com/firebase/quickstart-ios/tree/master/database/DatabaseExampleSwift).
The code runs fine, I have a new project set up in the Firebase admin console online, I have the new plist file set up and in xcode, and everything compiles fine. I just need code to easily access one measly piece of data! Plz help.
Thanks.
Here's my code (runs fine / is configured fine), but can't display the data:
class LatestNewsTableViewController: UITableViewController {
// get the Feed URL from Firebase:
lazy var FireBaseRef: FIRDatabaseReference = FIRDatabase.database().reference()
var FeedURLRef: FIRDatabaseReference!
var refHandle: FIRDatabaseHandle?
Then, in viewDidLoad(), I'm doing this:
FeedURLRef = FireBaseRef.child("AppGlobals").child("FeedURL")
refHandle = FireBaseRef.observeEventType(FIRDataEventType.Value, withBlock: { (snapshot) in
let FirebaseFeedURL = snapshot.value as! [String : AnyObject]
print("FirebaseFeedURL = " + String(FirebaseFeedURL))
})

Related

Reading and Writing to multiple Firestore Databases

I have a iOS app written in swift, and I've run into a problem. I have the data storage for my app on one firebase/cloud firestore project, and the licensing for this app (among others) on another firebase/cloud firestore server. I'm able to get the iOS app working with my data storage firebase project, but cannot for the life of me access my licensing server to validate logins and check if products are licensed. Is there a "correct" way of doing this/"proper" way to do this? Thanks!
edit: My data firebase project is working fine, in my appdelegate I have this code (keys changed obv):
let secondaryOptions = FirebaseOptions(googleAppID: "appIDKEY",
gcmSenderID: "senderID")
secondaryOptions.apiKey = "apiKey"
secondaryOptions.projectID = "project"
secondaryOptions.bundleID = "com.bundle.id"
secondaryOptions.clientID = "clientID.apps.googleusercontent.com"
secondaryOptions.databaseURL = "https://databaseurl.firebaseio.com"
secondaryOptions.storageBucket = "url.appspot.com"
secondaryOptions.appGroupID = nil
FirebaseApp.configure()
FirebaseApp.configure(name: "licensing", options: secondaryOptions)
then, in my Global Environment, I have this code:
let licensingApp = FirebaseApp.app(name: "licensing")
let licensingDB = Firestore.firestore(app: licensingApp)
let db = Firestore.firestore()
On the "let licensingDB = Firestore.firestore(app: licensingApp)" line, I get the error:
Cannot use instance member 'licensingApp' within property initializer; property initializers run before 'self' is available
What am I doing wrong?

getting innerText from ID element with swift not working with webView

I am using swift 4.2 so I am not sure if my code is outdated because many of the examples are not for the latest.
I have been trying many of the examples I have found here on stack but it seems they are outdated because of many references not valid working anymore.
I am trying to get the innerText of an element with a particular ID. Unfortunately I produce no results in successfully getting the value. Then I am trying to take result and put it in Firebase. If I use something like "test" instead of result it works fine, but I need result
Here is my code.
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
webView.evaluateJavaScript("document.getElementById('get_this_user').innerText") { (result, error) in
self.ref?.child("users").child("usernames").setValue(["get_this_user": result])
}
}

Does simply pulling all users from firebase database and putting them into an array efficient?

I have a simple iOS app that part of the app grabs all the users from firebase database so you can search them, and do different functions. Now my question is, if/when the app grows and there are thousands of users, does pulling all the users from the database and adding them to an array of [user]'s, still not crash or slow the app? I see so many people on youtube just loop through firebase and grab all the users. Please note I am excluding profile photos so there is no downloading images involved, just strings. I have some code I thought could solve this possible problem, but I am starting to wonder if there even is a problem with just fetching all the users from firebase and putting them into and array and then displayed in a tableview.
Here is some of my code right now, but it still I notice when I type in one letter, then turn airplane mode on, it downloaded all the users. I really need some help or some advice on this one, thanks.
var checklers = [String]()
func updateSearchResults(for searchController: UISearchController) {
if searchController.searchBar.text == "" {
filteredUsers = users
}
else {
print("refreshing")
if let uidi = FIRAuth.auth()?.currentUser?.uid {
view.addSubview(activityInd)
activityInd.startAnimating()
filteredUsers.removeAll()
checklers.removeAll()
let ref = FIRDatabase.database().reference()
ref.child("users").queryOrderedByKey().observe(.value, with: { snapshot in
if let userr = snapshot.value as? [String : AnyObject] {
for (_, velt) in userr {
if let usernamerr = velt["Username"] as? String {
if usernamerr.lowercased().contains(searchController.searchBar.text!.lowercased()) {
let userNew = usera()
if let name = velt["Full Name"] as? String, let uidd = velt["uid"] as? String {
userNew.name = name
userNew.username = usernamerr
userNew.uid = uidd
if self.checklers.contains(uidd) {
print("already")
}
else {
if userNew.uid != uidi {
self.filteredUsers.append(userNew)
self.activityInd.stopAnimating()
self.checklers.append(uidd)
}
print("added a user")
}
}
}
}
self.tableViewSearchUser.reloadData()
}
}
})
ref.removeAllObservers()
}
// filteredUsers = users.filter( { ($0.username?.lowercased().contains(searchController.searchBar.text!.lowercased()))! })
}
tableViewSearchUser.reloadData()
}
Please add any advice, thanks.
Just for searching one or two users, each time a user would need to fetch all the records and putting them all in an array (all in memory). You want SQL-where query function, but Firebase is just different and doesn't have it.
Problem with storing fetching all data approach:
1) Storing just all the user's information in an array of user objects is NOT scalable on client's device.
2) When the number of users gets to ten of thousands, a day worth of search by a single user will eat up a sizable amount of real time database read quota.
3) Stale user data, an user has to re-download all the users just becauase on user changed his name to Doggie1 to doggieTwo.
Solutions:
1) If you haven't done so already, I suggest the options of doing some server-side filtering first by following the best practice here:
Firebase Retrieving Data - Filtering
Downloading a sub-set of user that fits some criteria and then do a bit of client-side filtering. Still is problematic when users get to tens of thousands.
Firebase has a client-size data persistence feature, but in your case if there filtering rule doesn't fit your need, you need do you own caching with some persistent storage solution. Instead of putting the fetched object in an Array[User], I would store each in a database SQLite on iOS and Android apps.
2) Implement a ElasticSearch with the FlashLight plugin, this involves some extra setup (I know, I've been through it, I learned quite a bit), but it is well worth it for autocomplete and search functions that Firebase currently doesn't support.
A pluggable integration with ElasticSearch to provide advanced content searches in Firebase.

Trouble retrieving data from Firebase using .Value/.Child added in swift

i am working on a project where I am pulling data from firebase (which is "queued"). Essentially data is being saved w/ a time stamp so when it's called, it can be ordered sequentially (first in, first out).
The problem I am facing is when I retrieve the data on my app. From my research, on Stack overflow as well as firebase docs, .Value gives a snapshot and continues to listen to data when new data is added. However when new data is added it will take a new snapshot of the entire set (hence "duplicating data" on my app's array).
To get around this I have tried to instead use .ChildAdded, which works well to add new data to my array when new data is added to the firebase database. However it isn't adding the full data set (data that is already existing in the database), which is what I need in addition to new data being added.
Suppose firebase nodes as such:
App_Queue:
Category1:
Timestamp1:
Uid: User_1_uid
Timestamp2:
Uid: User_2_uid
Swift code (2.3):
Case1:
self.databaseRef.child("App_Queue/\(Category1)").queryLimitedToLast(15).observeEventType(.Value, withBlock: { (snapshot) in
if let userDict = snapshot.value as? [String:AnyObject]{
for each in userDict{
let timeIdExtract = each.0 as! String
self.timeIdArray.append(timeIdExtract)
print(self.timeIdArray)
}
//this gives me full snapshot of time stamps & a userId
//but if timestamp3 and user_3_uid is added to firebase, the array is appended with a new snapshot thus, duplicating items.
Case2:
self.databaseRef.child("App_Queue/\(Category1)").queryLimitedToLast(15).observeEventType(FIRDataEventType.ChildAdded, withBlock: { (snapshot : FIRDataSnapshot) in
if let userDict = snapshot.value as? [String:AnyObject]{
for each in userDict{
let timeIdExtract = each.0 as! String // Every follwers ID.
self.timeIdArray.append(timeIdExtract)
print(self.timeIdArray)
}
//this gives me only new items added, but not already added.
// if timestamp3 and user_3_uid is added the array is appended with this new item. But timestamp1 & timestamp2 not added
Case 3:
I have tried a hybrid of Case1 (instead use .observeSingleEventOfType()) & Case2, by adding a self.databaseRef.removeAllObservers() after the code in case 1, and then turning on the .ChildAdded observer for case2. It almost works.... added initial snapshot via case 1, then listens however if say, timestamp2 is recently added it will append this again when Case2 is called, thus duplicating the array.
So my question: how the heck do I go about getting existing objects in the database AND adding on new ones, without duplicating data in the array?
EDIT
Im silly-- had some extraneous code after the block which was throwing things off. DOH! For anyone experiencing issues, first place to check! also .ChildAdded paired with observeEventType did the trick. (takes all previous data already in DB + adds new data as it comes in).
self.databaseRef.child("App_Queue/\(Category1)").queryLimitedToLast(15).observeEventType(.ChildAdded, withBlock: { (snapshot) in
...
Im silly-- had some extraneous code after the block which was throwing things off. DOH! For anyone experiencing issues, first place to check! also .ChildAdded paired with observeEventType did the trick. (takes all previous data already in DB + adds new data as it comes in).
self.databaseRef.child("App_Queue/\(Category1)").queryLimitedToLast(15).observeEventType(.ChildAdded, withBlock: { (snapshot) in
...

Array data values load correctly in simulator but returns Nil values on phone

Hello folks and thanks for your help,
I am currently running an Xcode 8 project using swift 3 and Firebase Database. I am pulling over data from a CLLocationSearch using Core Location Data from a previous table Search UI. The data comes over and populates the "StoreUI" where I have this function addBtn that kicks off the code below to send the data to Firebase Database.
My issue is as follows: When I run the app with xCode's simulator, everything works fine. The data pulls together, fills the array properly, and when I break the code after setting up the array, I see all the proper values before it eventually posts to firebase. Again, using the simulator everything works 100%.
However, when I run the app from the phone, nothing happens in the array. All the values come back as nil for each segment resulting as 8 nil values in my array. Because the array has nil values it will crash the app during the post command.
What am I doing wrong, or what do I need to do, to get this running correctly both in the simulator and the phone testing?
So far I tired moving the variable setup outside the function, but I get the same results. I was thinking of moving the "let post" code into it's own function, but I am not sure that will help.
Thanks again for your help!
#IBAction func addBtn(_ sender: AnyObject) {
// Save Store Info.
let uniqueRef = storeRef.childByAutoId()
geoFire = GeoFire(firebaseRef: geoRef)
let lat = storeData?.placemark.coordinate.latitude
let long = storeData?.placemark.coordinate.longitude
let post : [String: String] = ["StoreName" : (storeData?.name)!,
"subThouroughfare" : (storeData?.placemark.subThoroughfare)!,
"Thouroughfare" : (storeData?.placemark.thoroughfare)!,
//"subLocality" : (storeData?.placemark.subLocality)!,
"locality" : (storeData?.placemark.locality)!,
"subAdministrativeArea" : (storeData?.placemark.subAdministrativeArea)!,
"administrativeArea" : (storeData?.placemark.administrativeArea)!,
"postalCode" : (storeData?.placemark.postalCode)!,
"phoneNumber" : (storeData?.phoneNumber)!
]
let key: String = uniqueRef.key
geoFire!.setLocation(CLLocation(latitude: lat!, longitude: long!), forKey: key)
uniqueRef.setValue(post)
}
This was an issue with coding my 3rd party developer did, having issues with the MKMapItem. He has fixed my issue and this case is closed.

Resources