Remove an entire child from Firebase using Swift - ios

I'd like to write a function to remove an entire child from Firebase. I'm using XCode 10 and swift 3+.
I have all the user info of the child I'd like to delete so I assume the best call would be to iterate through every child and test for the matching sub child value but it would be great if there was a faster way.
Thanks for the help!
Heres what I'd like to delete
I assume testing for epoch time then removing the whole node would be ideal. Also not sure how to do this

I understand you don't have access to the key of the node you want do delete. Is that right? Why not? If you use the "observe()" function on a FIRDatabaseQuery object, each returned object should come with a key and a value.
Having a key it is easy to remove a node, as stated in the Firebase official guides.
From the linked guide,
Delete data
The simplest way to delete data is to call removeValue on a reference
to the location of that data.
You can also delete by specifying nil as the value for another write
operation such as setValue or updateChildValues. You can use this
technique with updateChildValues to delete multiple children in a
single API call.
So, you could try:
FirebaseDatabase.Database.database().reference(withPath: "Forum").child(key).removeValue()
or
FirebaseDatabase.Database.database().reference(withPath: "Forum").child(key).setValue(nil)
If you can't get the key in any way, what you said about "iterating" through the children of the node could be done by using a query. Here's some example code, supposing you want all forum posts by Jonahelbaz:
return FirebaseDatabase.Database.database().reference(withPath: "Forum").queryOrdered(byChild: "username").queryEqual(toValue: "Jonahelbaz").observe(.value, with: { (snapshot) in
if let forumPosts = snapshot.value as? [String: [String: AnyObject]] {
for (key, _) in forumPosts {
FirebaseDatabase.Database.database().reference(withPath: "Forum").child(key).removeValue()
}
}
})
Here you create a sorted query using as reference "username" then you ask only for the forum posts where "username" are equal to Johanelbaz. You know the returned snapshot is an Array, so now you iterate through the array and use the keys for deleting the nodes.
This way of deleting isn't very good because you might get several posts with the same username and would delete them all. The ideal case would be to obtain the exact key of the forum post you want to delete.

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)")
}

Append element to Firebase Array

How I could append an element to an array like that:
Using this code I'm overriding the old data:
let toUpdate = [book.id]
self.refUsers.child(localUser.key!).child("booksPurchased").setValue(toUpdate, withCompletionBlock: { (error, _) in
You could use this method: firebase.firestore.FieldValue.arrayUnion()
Example with angularfire2:
this.afs.collection('collection').doc(id).update( {
array: firebase.firestore.FieldValue.arrayUnion( 'newItem' )
});
For more information: https://firebase.google.com/docs/reference/js/firebase.firestore.FieldValue#arrayunion
In this case, you will have to read the existing data, then write it back with the new value added. Arrays like this are not always the best way to store lists of data if you want to perform a lot of append operations. For that, you're better off pushing data into a location using childByAutoId.
Reading and writing lists
Append to a list of data
Use the childByAutoId method to append data to a list in multiuser applications. The childByAutoId method generates a unique key every time a new child is added to the specified Firebase reference. By using these auto-generated keys for each new element in the list, several clients can add children to the same location at the same time without write conflicts. The unique key generated by childByAutoId is based on a timestamp, so list items are automatically ordered chronologically.
You can use the reference to the new data returned by the childByAutoId method to get the value of the child's auto-generated key or set data for the child. Calling getKey on a childByAutoId reference returns the auto-generated key.
You can use these auto-generated keys to simplify flattening your data structure. For more information, see the data fan-out example.
-https://firebase.google.com/docs/database/ios/lists-of-data
You could set the values of the keys in the array to true, and then set the value directly in an update.
So if 'newId' is the new item to add, maybe something like:
const update = {
[`/users/${localUser.key}/booksPurchased/${newId}`]: true]
}
firebase.db.ref().update(update);
Firebase docs example of an update:
https://firebase.google.com/docs/database/web/read-and-write

Firebase observeEventType .childAdded doesn't work as promised

When I call this observe function from in my viewcontroller, the .childadded immediately returns a object that was already stored instead of has just bin added like .childadded would suspect.
func observe(callback: RiderVC){
let ref = DBProvider.Instance.dbRef.child("rideRequests")
ref.observe(DataEventType.childAdded) { (snapshot: DataSnapshot) in
if let data = snapshot.value as? NSDictionary {
let drive = cabRide(ritID: ritID, bestemming: bestemming,
vanafLocatie: vanaf, taxiID: taxiID, status: status)
print(drive)
callback.alertForARide(title: "Wilt u deze rit krijgen?", message: "Van: \(vanaf), Naar: \(bestemming)", ritID: ritID)
}
}
}
When I try this function with .childchanged, I only get a alert when it is changed like it suppose to do, but when doing .chiladded, it just gets all the requests out of the database and those requests were already there.
When I add a new request, it also gives an alert. So it works, but how can I get rid of the not added and already there requests?
Does anybody know this flaw?
This is working exactly as promised. From the documentation:
Retrieve lists of items or listen for additions to a list of items.
This event is triggered once for each existing child and then again
every time a new child is added to the specified path. The listener is
passed a snapshot containing the new child's data.
That might seem weird at first, but this is generally what most developers want, as it's basically a way of asking for all data from a particular branch in the database, even if new items get added to it in the future.
If you want it to work the way you're describing, where you're only getting new items in the database after your app has started up, you'll need to do a little bit of work yourself. First, you'll want to add timestamps to the objects you're adding to the database. Then you'll want to do some kind of call where you're asking to query your database by those timestamps. It'll probably look something like this:
myDatabaseRef.queryOrdered(byChild: "myTimestamp").queryStarting(atValue: <currentTimestamp>)
Good luck!

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)
}
})
}
})

Removing All Items Under A Node Firebase

I am trying to remove all the children under a node. Is there a way to delete all the items under a node? The structure is like:
lastMessages
- mainId
- timestampedId
- keys:values
What I want to do is, by using mainId, delete all the items under it. Actually there's only one timestampedId at a time as this is for lastMessages. That's why I thought I should delete all items under mainId just before writing my new value. Is there a way to achieve that; or is there any better ways than I thought?
let ref = Firebase(url: path)
let myRef = ref.childByAppendingPath(mainId)
// how to delete all items under myRef?
Simply call myRef.removeValue()
Explained in the docs
The simplest way to delete data is to call removeValue on a reference to the location of that data.

Resources