Firebase Read to Swift NSArray / or String Swift 3.0 - ios

I am working on a project that reads from a Dictionary .plist that is located in the documents directory. I am currently migrating to Firebase. I have the "Write" working to -> Firebase. I also have the "Read" from <- Firebase working. The challenge that I am having is re-formatting the data the way I need it, in order to run it through my RegEx filter. I am not sure what to use to do this, a Parser or what... Just need some direction on the best way to pull the values out from the Firebase data that I read. I have spent about 10 hours trying different ways of formatting the Firebase data, but constantly get errors telling me that I can't change "Any" to "String" or "Any" to "Array". If you have not noticed, I am not a seasoned coder...
I am using Swift 3.0
This is the code that I have. (Note: I have the Firebase SDK installed and this code is just in the viewDidLoad func. for now). Also, I am using an NSObject Class that is outside of my viewDidLoad() for Post.
Thank you
var posts = [Post]()
class Post: NSObject {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//This is the code that reads from FireBase
let ref = Database.database().reference().child("List").queryOrderedByValue()
ref.observe(.value, with: { snapshot in
print(snapshot.value ?? "can't print Values")//snapshot.value is what prints out to the console
self.posts = []
if let snapshots = snapshot.children.allObjects as? [DataSnapshot] {
for snap in snapshots {
if let postDict = snap.value as? Dictionary<String, AnyObject> {
let post = Post()
post.setValuesForKeys(postDict)
self.posts.append(post)
}
}
}
})
}
The output of the code in the viewDidLoad() produces this output to the console
{"-KmUr43ZPycmz7G3IBlA" = "Adding something";
"-KmUr6M3F6HSEIAMbaVa" = "This is my next one";
"-KmUr8xe2vDtLMZn84kP" = "Emoji";
"-KmWaviTHnzD_EBatRU8" = "next definition";
"-KmYMTqVXHhanJkkId4r" = "Rich is Cool";}
I would like to pull out the values of the above output two different ways
and that is as an Array / NSMutableArray, and a String / NSMutableString
This is what I would like the Array to look like
["Adding something", "This is my next one", Emoji", "next definition", "Rich is Cool"]
This is what I would like the String to look like
Adding something, This is my next one, Emoji, next definition, Rich is Cool
Thank you so much for taking a look at this

Related

Retrieving user info from firebase

I know this question is asked a lot, but none of the solutions seem to be working for me(I have been trying multiple solutions from threads like Read data from firebase swift but it doesnt print anything to my console).
I am trying to retrieve the type of user from my database, but I dont know how to.
func pushUserInfo(){
let ref = Database.database().reference()
let infoDict = ["First name": firstName.text!, "Last name": lastName.text!, "hours": 0, "isUser" : "user"] as [String : Any]
let users = ref.child("users").child(username)
users.setValue(infoDict)
}
The part that says ["type": "user"] has two options, either "user" or admin
The screenshot above is of the Firebase realtime database.
I am trying to retrieve the type of the user, but I have no idea how. Please help me figure this out, and if possible, explain the code, because I dont really understand too much about Firebase in general. I tried reading their firebase docs, but I still dont really get it.
It looks like you're setting the data fine except that your username property appears to be a concatenated string of two optionals (maybe firstName.text and lastName.text. So this will make it impossible to query. The first step is to unwrap these into a string:
let username = "\(firstName.text!) \(lastName.text!)"
Once you've done that, you can query for that data like this:
let username = "\(firstName.text!) \(lastName.text!)"
let ref = Database.database().reference().child("users/\(username)")
ref.observeSingleEvent(of: .value, with: { (snapshot) in
// Now you can access the type value
let value = snapshot.value as? NSDictionary
let type = value?["type"] as? String ?? ""
}) { (error) in
print(error.localizedDescription)
}
You may also want to reconsider having spaces in your property names (maybe use lastName instead of last name). It will be easier for your code later on.

swift 4 / firebase Super Simple read / write. Can't read

Super newbie! I just want to practice reading and writing for Firebase. My write code works! I've consulted dozens of examples online and still can't get the read portion working.
As a newbie, I've also tried some simple debug techniques but no help.
Exactly how do I fix this code so that the read happens (and I know it happened because the code prints to terminal)?
I'd really like a Swift 4 based solution, thanks.
My repo
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var ref:DatabaseReference!
var refHandle:DatabaseHandle!
ref = Database.database().reference()
ref.child("test").setValue("name: Bruce")
//Nothing below works
refHandle = ref.child("test").observe(DataEventType.childAdded, with: { (snapshot) in
let info = snapshot.value as? String
print(info as Any)
})
}
Note that my Firebase DB is enabled for READ and WRITE. I have also tried observeSingleInsance (or whatever it is when you read just once).
I know the write works because i can see the data in the Firebase console
I believe your problem is in setValue("name: Bruce"), where you set the node "test" to "name: Bruce", as opposed to "name": "Bruce"
if you change that to say
updateChildValues(["name": "Bruce"])
surely it would work.
Go to your Firebase console, and perform following steps which is identify in image.
Read like that as you currently trying to listen to child add , so replace childAdded with value , Also you should wait until write process happens and then read , suppose launch app again for read only
refHandle = ref.child("test").observeSingleEvent(of: .value, with: { (snapshot) in
let info = snapshot.value as? String
print(info as Any)
})
Do you have this enabled? Then try changing it to
Database.database().isPersistenceEnabled = false
Otherwise try this and print the snapshot you get (You don't actually need the handle):
ref.child("test").observe(.value, with: { (snapshot) in
print(snapshot)
})

Retrieving my posts from firebase and display it on my collectionView Cells? ios

override func viewDidLoad() {
super.viewDidLoad()
getImageUrl()
}
func getImageUrl(){
ref.child("posts").queryOrderedByKey().observeSingleEvent(of: .value) { (snapchot) in
let postsss = snapchot.value as! [String : AnyObject]
for (_,posst) in postsss {
if let uid = posst["userID"] as? String{
if uid == Auth.auth().currentUser?.uid{
if let myPostURL = posst["pathToImage"] as? String{
self.imageURLs.append(myPostURL)
}
}
}
}
}
}
I want my code to go through all the posts on Firebase and then check if their userID matches the currentusers uid, if they matched which means they are my images. then send the URL in pathToImage to an array in my code called imageURLs()[ "" ].but I don't know how to to that??. I am using SDWebImage to display my images to the collectionView cell. i have tested it and it works fine if i copy and paste a random URL in the array called imageURLs[ "URL here" ]
I am very new to Swift and Firebase, so any help would be greatly appreciated!! :)
HERE IS AN IMAGE OF MY FIREBASE FILES.
https://ibb.co/bXLMcb
Psst! posts/pathToImage holds the URL so that's the one i want to retrieve.
users/urlToImage is just a profile picture. i don't really need it right now
To locate specific data within a node a Query is used.
While iterating over the nodes works, if there's a million nodes it's going to take a long time and tie up the UI while waiting for that to happen.
The bottom line is; if you know what you are looking for - in this case a uid - then a query is a super simple solution.
let postsRef = self.ref.child("posts")
let query = postsRef.queryOrdered(byChild: "userID").queryEqual(toValue: "uid_0")
query.observeSingleEvent(of: .value) { (snapshot) in
if snapshot.exists() {
for child in snapshot.children { //.value can return more than 1 match
let snap = child as! DataSnapshot
let dict = snap.value as! [String: Any]
let myPostURL = dict["urlToImage"] as! String
self.imageURLs.append(myPostURL)
}
} else {
print("no user posts found")
}
}
With the above code, we first create a reference to our posts node. Then a query that will only return this users (uid_0) posts.
We then iterate over the snapshot of posts and add them to the array.
This is much more efficient that loading and evaluating every node in the database.
See Sorting And Filtering data for more information.
You should think about storing an index of all your users posts somewhere in your database. That way you don't need to observe all posts every time. This is called denormalization. Firebase has an article in their docs about organizing your database.
Here's some information regarding firebase filtering in swift.
The best solution is to add a separate node that has a list of "post IDs" organized by user. Then you could observe that node, and only download each post specifically by the returned ID. Here's a link about flattening data structures in firebase. It would look something like this.
"posts":{
"somePostID":{
"timestamp": "0200231023",
"postContent": "here's my post content",
"authorUID" : "0239480238402934"
} ...
},
"postsByGivenUID":{
"someAuthorID":{
"somePostID": "true",
"somePostID": "true",
},
"someOtherAuthorID":{
"somePostID": "true",
"somePostID": "true",
"somePostID": "true"
}
}
This is actually a much bigger problem than just changing how you structure your code. For scalability sake, you're going to have to reevaluate how you structure the data in firebase altogether.
Then, you can nest your firebase query, sort of like this:
ref.child("postByGivenUID").child("Auth.auth().currentUser?.uid").observe(.childAdded) { (snapshot) in
ref.child("posts").child(snapshot.value).observeSingleEventOfType(of: .value) { (snap) in
// your actual post data will be here
// that way you won't be downloadin ALL posts EVERY time
}
}

iOS Swift: retrieve an entry from the database for the user currently logged in

How do I retrieve a value (other than username and user id, which seem easier to get) for the current user from the database.
Ironically, I can set the value as follows and that works just fine:
let databaseRef = FIRDatabase.database().reference()
userID = (FIRAuth.auth()?.currentUser?.uid)! as String
databaseRef.child("users").child(userID!).child("TermCond").setValue("Yes")
But for the life of me I cannot work out what to put instead of setValue if I simply want to retrieve the current TermCond value. I thought just using value as for example in
let DesiredValue = databaseRef.child("users").child(userID!).child("TermCond").value as? String
Would suffice, but nothing works. I am confused why retrieving the value should be more difficult than setting it.
To "read" a value from Firebase, you need to add a reference listener that gets called every time that value changes.
In your case, that could be something like:
let databaseRef = FIRDatabase.database().reference()
databaseRef.child("users").child(userID!).child("TermCond").observe(FIRDataEventType.value, with: { (snapshot) in
let desiredValue = snapshot.value as? String
})
This block of code will get triggered every time your value changes. If you only want to read it once, you can use observeSingleEvent:of:with instead of observe:with.
This is as described in the Firebase documentation: https://firebase.google.com/docs/database/ios/read-and-write
I recommend you read their entire Documentation to get an idea of how Firebase works, as it is very different from traditional databases.
I can also recommend the following tutorial if you'd like to learn a bit more about the Firebase Database and how it works: https://www.raywenderlich.com/139322/firebase-tutorial-getting-started-2
I've solved this now (based on Aleksander's reply). The way I did it is as follows.
databaseRef.child("users").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
self.desiredValue = value?["TermCond"] as? String ?? ""
self.LabelToShow.text = self.desiredValue!
}) { (error) in
print(error.localizedDescription)
}
This works absolutely fine and shows the value of TermCond in the LabelToShow on my iOS screen.

Problems with structuring and retrieving data from Firebase in Swift

I am designing a litte quiz app but I'm having trouble while retrieving the game data.
As you can see in the picture I have an JSON object that contains many single games. Each single game has a unique id. My first problem is that each of the games can be available in multiple languages. I know that I could download the hole snap and then looping throw each game but that would mean really long loading times while the app is growing.
In short form:
I need to retrieve the following data from the JSON above:
A random game wich is available in a specific language (need to have the key en for example)
All games that are available in "en" but not yet in "de"
If it is easier to restructure the data in the JSON, please tell me.
Thanks for helping me.
Answer to your first part :-
let enRef = FIRDatabase.database().reference().child("singleGames").child(singleGamesUID).child("en")
enRef.observeEventType(.Value, withBlock: {(snap) in
if let enQuizQuestion = snap.value as? [String:AnyObject]{
//Question exists : Retrieve Data
}else{
//Question in english doesn't exist
}
})
For your second part
Since you are trying to save iteration time might i suggest you also save your singleGames id in a separate languagesBased nodes, there is a command in firebase that allows you to search for some keyValues in your child node's , but even that i think would be executing a search algorithm which might be a little more time consuming :--
appServerName:{
singleGames :{
uid1:{......
......
...},
uid2:{......
......
...},
uid3:{......
......
...}
},
enQuestions:{
uid3 : true
}
deQuestions:{
uid1 : true,
uid2 : true
}
}
Now all you gotta do :-
let rootRef = FIRDatabase.database().reference().child("deQuestions").observeEventType(.Value, withBlock: {(qSnap) in
if let qDict = qSnap.value as? [String:AnyObject]{
for each in qDict as [String:AnyObject]{
let deUID = each.0
}
}else{
//No question in dutch language
}
})

Resources