Firebase fetch multiple results - ios

I was wondering if there is any way with swift and firebase, to get multiple numbers from the same child? and average all the numbers.
Example,
Every authorized user saves a number to the database. Then when they look at there number in a saved section it averages all other users numbers and compares it against theres.
I can get all the data to save, and I can get the data to send back info, but it only sends one number from the list
I have tried different ways but I can't get it to work. Any help would be awesome.
I would post some code but none of it is working real well
Thanks again in advance

For your example, you would use childByAutoID to create a random unique identifier for your user. To get multiple values from one child you would use a comma, when setting the childs value. Like this,
struct getInput {
var inputType: String!
}
//copying and pasting this code into your code will not work, however
//you should be able to understand why and how this works.
let getUsername = getInput(inputType: usernameTextField.text!)
let getPassword = getInput(inputType: passwordTextField.text!)
let userReference = database.reference().child("users")
userReference.setValue(getUsername.inputType)
let childByAutoID = userReference.childByAutoId()
childByAutoID.setValue(["username": getUsername.inputType, "password": getPassword.inputType])

Related

How can I access firebase directory names as an array?

I'm trying to access department and course information for an iOS app for students to buy/sell textbooks.
Right now I have two pickerViews. I'd like to select the department in one and have the relevant courses load into the second. What kind of call can I make to get an array of just the department names when structured as below?
So here I would want to access an array ["AHSS", "AIE", "ANTH"]. Then afterwards, I'd make another call depending on the selection. For AIE, I'd want the array ["330", "340"].
I'm unsure how I can just get the directory names as an array and not the values they eventually lead to?
For anyone else that might have had this question. #Nikunj Kumbhani directed me in the right direction and I eventually got this which lists the key values.
myDatabase.child("departments").child("\(selectedDepartment ?? "AHSS")").observeSingleEvent(of: .value) { (snapshot) in
if let myData = snapshot.value as? NSDictionary {
for name in myData.keyEnumerator() {
stringList.append("\(name)")
}

Observing data on Firebase vs. checking an array?

I've got a situation where I've got a tableview being filled with names from Firebase.
When the view loads in, I pull all the necessary names from firebase, load them into an array, and base my tableview off that array.
I have an "add" button that takes whatever's in a text field and adds that name to both firebase and their list.
What I do not want to allow is for people to add a name that they have already added.
I'm pulling the names they've added from Firebase like:
users
209384092834
Names
Bob
Sue
so if the user were to type in Rob, it'd add it under that "names" bit, but if they typed in Bob/Sue it wouldn't allow them to add that again.
The two ways I see of doing this are to check if the name a user is wanting to add is in the array I'm filling on load, or to check against the names that are under their Names child on firebase.
Are there any strong arguments for using one over the other. Is it a "big deal" to run an observer to firebase? I feel like using firebase here is "safer" than checking the array..like what if the users net is so or inturrupts, the array hasn't filled up yet, and they type in a name to add, add it, and everything is just a mess. I don't even know if something like that COULD happen.
Any advice here on which direction to take and why?
Important :- Never use Arrays or Tuples to store in Firebase Database, always prefer Dictionary
Make your DB look something like this :-
{ users : {
209384092834 : {
Names: {
Bob : True,
Sue : True
}
}
}
}
I would suggest you use a third path :-
Check if that name exists by referring to that child node and checking by taking a particular snap of that path instead of the entire list..
rootRef.child("users").child(timeStamp).child("Names").child(textField.text!).observeEventType(.Value, withBlock: {(snapshotRecieved) in
if snapshotRecieved.exists()
{
//Show Alert that user Exists i.e if user is rob/sue in your case
}else{
let ref = rootRef.child("users").child(timeStamp).child("Names")
ref.observeEventType(.Value, withBlock: {(snapshot) in
if let namesDict = snapshot!.value as? NSMutableDictionary{
namesDict.setObject("True",forKey:textField.text!)
ref.setValue(namesDict)
}
})
}
})

Connecting remote search results with local database using CoreData

Assume we have simple data model with single entity User; simple tableView_friends with fetchedResultsController_friends for show users - friends.
Assume we have search bar for searching all (not only friends) users in service, and for every typed in it character we perform search request to server, which return to us somehow filtered by character User objects. Some of this objects can already be inside local database. By app logic we don't really must save all this results in local database forever (but ok, we can, we can clear local database time to time); on other hand, if we will perform any action on some searched user, we must store this user. We want to show list of searched user in other tableView_search with fetchedResultsController_search.
Question: should I use same context for fetchedResultsController_friends and fetchedResultsController_search? If no, how can I handle situation, when I wish to edit searched user, which already exists in database and probably already local edited? If yes, how can I setup predicate for fetchedResultsController_search (server perform its own logic for search by character, which can be changed) for show exactly same result as from server?
We recently implemented a search feature in our application and had a similar issue, We had local data in core data and also remote data from our API.
You have a few options that we explored:
Save your data into core data from the API as it is retreived and
then the fetched results controller will do the rest
Manage the merge of the data yourself, you can still use NSFetchedResults controller to an extent but need to do more work
We didn't want to save all of the information returned from the API unless it was needed (the user selected it), so we come up with a simple solution that worked for our app. This may not work directly for your app, you may need a completely different solution or change some of the things we done to suit.
Firstly, To explain what we are dealing with, we had a Article entity in core data which contains around 25 properties, the API returns article objects as JSON data with the same data.
What we decided to do was to create a class which represents a simple version of an article (just enough data to show in a list view and reference it later in the API or core data) which looked something like this:
class SearchResult: NSObject {
var id:String?
var title:String?
var imageUrl:String?
var url:String?
// core data entity
init(article:Article) {
self.id = content.contentId
self.title = content.title
self.featuredImageURL = content.absoluteImagePath()
self.urlAlias = content.urlAlias
self.publishedAt = content.publishedAt
}
init(articleDictionary:NSDictionary) {
self.id = articleDictionary.objectForKeyNotNull("id") as? String
self.title = articleDictionary.objectForKeyNotNull("title") as? String
self.url = articleDictionary.objectForKeyNotNull("url") as? String
if let imageUrl = articleDictionary.objectForKeyNotNull("imageUrl") as? String {
self.imageUrl = imageUrl
}
}
}
Now using this, we can create once of these from either the core data results or from the API results. Our tableview datasource is just an array
var dataSet = [SearchResult]()
We use the NSFectchResultsController delegate methods to add/remove/re-order core data elements from the dataSet after the initial load and when we get API data we'll do something like:
dataSet = Array(Set(apiResponseArray + dataSet))
This will take an array of SearchResult items from the API, merge them with the current result set and remove duplicates. casting to a set and then back to an array will give you an array of unique results as a Set is made of unique values only.
See this reference which should help with how the delegate methods would work

Cross reference columns in Parse to decide which users to Display on a view controller. Swift, user search settings

What I am trying to figure out is how to only display users that meet the setting requirements that the user previously saved on a different ViewController. Ok so on set up the current user has selected their genre and instrument and it has saved in columns in Parse called "genre" and "instrument" as Strings. Then on the search settings page the user has selected that they would like to search for lets say "Rock" as the genre and "Acoustic guitar" as the instrument. Both of these then get added to Parse under the columns "genreSearch" and "instrumentSearch".
So I know I need to make a query and display it on the ViewController that the users are displayed on but I don't know how. I am trying to basically cross reference the column "genre" of other users against the current users column "genreSearch". I imagined it would be something like this:
genreQuery.whereKey("username",notEqualTo:PFUser.currentUser()!.username!)
genreQuery.whereKey("genre", notEqualTo:PFUser.currentUser()!username!)
genreQuery.whereKey("genreSearch", equalTo:PFUser.currentUser()!)
genreQuery.findObjectsInBackgroundWithBlock { (users: [AnyObject]?,
error: NSError?) -> Void in
if error == nil {
for user in users! {
if self.genre == self.genreSearch {
print("These two strings are considered equal")
appUsers.append(user as! PFUser)
}
self.resultsPageTableView.reloadData()`
At the top of my VC I have as I am storing and displaying all the users in a cell which also links to another VC to show more details.
var genre = [String]()
var genreSearch = [String]()
var appUsers = [PFUser]()
I have read Parse docs and to be honest now I am more confused as where to go.
I have searched the internet for past few days and it is all js and objc both of which I have zero experience in. If someone could point me at a start or even guide me in what to do so I can learn.
In the cell I am displaying the users details like so:
let singleCell: CustomCell = tableView.dequeueReusableCellWithIdentifier("mySingleCellid") as! CustomCell
let userObject = appUsers[indexPath.row] as PFObject
singleCell.userName.text = userObject["name"] as? String
// etc
return singleCell
This part of the query
genreQuery.whereKey("genreSearch", equalTo:PFUser.currentUser()!)
is wrong because you're trying to check that an array of strings contains a user object (a pointer) - which will always fail.
While you have genreSearch on the server for the current user it's easier to just replace that part of the query with
genreQuery.whereKey("genreSearch", containedIn:PFUser.currentUser()!["genreSearch"])
which instead asks for the genreSearch array on each user tested to contain at least one of the current users array of genreSearch
I was going about it all wrong what I needed to do was take genreSearch from the Parse DB and store it in the app itself as a variable. This variable is then a key for my PFQuery and I use it to filter out the people that don't have it. I then use genreSearch as a condition skipping the people that don't have it and adding the people that do. I nearly have it cracked except for the last few coding of it. Instead of editing this question to ask for help I have asked and posted my new code to a new SO question

Query users by name or email address using Firebase (Swift)

I'm quite new to Firebase and Swift and I'm having some trouble when it comes to querying.
So there are basically two things I'd like to do:
Query my users and find only those that contain a certain String in their name (or email address) and add them to an array.
Get all of my users and add them to an array.
The relevant part of my data for this question looks like this:
As you can see, I'm using the simplelogin of Firebase (later I'd like too add Facebook login) and I'm storing my users by their uid.
A part of my rules file looks like this:
"registered_users": {
".read": true,
".write": true,
".indexOn": ["name"]
}
So everybody should have read and write access to this part of my data.
I also read the "Retrieving Data" part of the Firebase iOS Guide on their website and according to that guide, my code on getting all the users names and email addresses should work, at least I think so. But it doesn't. Here is my code:
func getUsersFromFirebase() {
let registeredUserRef = firebaseRef.childByAppendingPath("registered_users")
registeredUserRef.queryOrderedByChild("name").observeSingleEventOfType(.Value, withBlock: { snapshot in
if let email = snapshot.value["email"] as? String {
println("\(snapshot.key) has Email: \(email)")
}
if let name = snapshot.value["name"] as? String {
println("\(snapshot.key) has Name: \(name)")
}
})
}
I noticed, that in the firebase guide, they always used the type ChildAdded and not Value, but for me Value makes more sense. The output with Value is nothing and the output with ChildAdded is only one user, namely the one that is logged in right now.
So my questions are:
Can I do this query with my current data structure or do I have to get rid of storying the users by their uid?
If yes, how would I have to change my code, to make it work?
If no, what would be the best way to store my users and make querying them by name possible?
How can I query for e.g. "muster" and get only the user simplelogin:1 (Max Mustermann)?
I hope my description is detailed enough. Thx in advance for your help.
Supplement:
The weird thing is, that the "Retrieving Data" guide says, that querying and sorting the following data by height is possible.
Data:
Querying code:
And isn't that exactly the same that I intent to do?
I have run into similar situations where I wanted to pull out data from child nodes.
https://groups.google.com/d/msg/firebase-talk/Wgaf-OIc79o/avhmN97UgP4J
The first thing I can recommend is to not think of Firebase query's as SQL queries as they are not. They are like a light duty query.
Secondly, you need to flatten your data if you want to query, as a query only goes one level deep (can't really query data in child notes)
Lastly - if you don't want to flatten your data, one conceptual option to answer your question;
If possible, ObserveSingleEventOfType:FEventTypeValue on the
registered users node. This will read all of the registered users into a snapshot.
Iterate over the snapshot and read each user into an array (as dictionary objects)
Then use NSPredicate to extract an array of users that you want.
I've run numerous tests and performance wise, it's negligible unless you have thousands of users.
Hope that helps!
To answer your questions
1) Yes, you can query with your current structure. A query can go 1 child deep, but not within a child's children.
2) If yes, how would I have to change my code, to make it work?
Here's a quickie that queries by a users last name:
Firebase *usersNodeRef = your users node 'registered_users'
FQuery *allUsersRef = [usersNodeRef queryOrderedByChild:#"lastName"];
FQuery *specificUserRef = [allUsers queryEqualToValue:#"aLastName"];
[specificUser observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) {
NSDictionary *dict = snapshot.value;
NSString *key = snapshot.key;
NSLog(#"key = %# for child %#", key, dict);
}];
How can I query for e.g. "muster" and get only the user simplelogin:1 (Max Mustermann)?
In your uses node structure, the users are store in nodes with a key.. the key is the simplelogin:1 etc. snapshot.key will reveal that. So it's key/value pair deal...
value = snapshot.value
key = snapshot.key

Resources