D. Finna D. Finna - 2 months ago 35
Swift Question

Update specific part of firebase database swift

I am having a hard time trying to figure out, how I can change/update a specific part of my firebase database through swift. To give you an example of how my firebase database is structured, here you have a photo:
enter image description here

I am trying to update the likesForPost +1 everytime someone hits the like button that I have in my tableViewController. The important part is that every likesForPost should not be updates, just the one where the button is. I hope you understand my situation and that you can help me :-)

My struct

struct Sweet {
let key: String!
let content: String!
let addedByUser: String!
let profilePhoto: String!
var likesForPost: String!
let itemRef: FIRDatabaseReference?



init (content: String, addedByUser: String, profilePhoto: String!, likesForPost: String!, key: String = "") {
self.key = key
self.content = content
self.addedByUser = addedByUser
self.profilePhoto = profilePhoto
self.likesForPost = likesForPost
self.itemRef = nil
}

init (snapshot: FIRDataSnapshot) {
key = snapshot.key
itemRef = snapshot.ref

if let theFeedContent = snapshot.value!["content"] as? String {
content = theFeedContent
} else {
content = ""
}

if let feedUser = snapshot.value!["addedByUser"] as? String {
addedByUser = feedUser
} else {
addedByUser = ""
}

if let feedPhoto = snapshot.value!["profilePhoto"] as? String! {
profilePhoto = feedPhoto
} else {
profilePhoto = ""
}

if let feedLikes = snapshot.value!["likesForPost"] as? String! {
likesForPost = feedLikes
} else {
likesForPost = "0"
}

}

func toAnyObject() -> AnyObject {
return ["content":content, "addedByUser":addedByUser, "profilePhoto":profilePhoto!, "likesForPost":likesForPost]
}
}


My UITableViewController

import UIKit
import FirebaseDatabase
import FirebaseAuth
import FBSDKCoreKit

class feedTableViewController: UITableViewController {



@IBOutlet weak var loadingSpinner: UIActivityIndicatorView!


var facebookProfileUrl = ""
var dbRef: FIRDatabaseReference!
var updates = [Sweet]()

override func viewDidLoad() {
super.viewDidLoad()
loadingSpinner.startAnimating()

dbRef = FIRDatabase.database().reference().child("feed-items")
startObersvingDB()

}

func startObersvingDB() {
dbRef.observeEventType(.Value, withBlock: { (snapshot: FIRDataSnapshot) in
var newUpdates = [Sweet]()

for update in snapshot.children {
let updateObject = Sweet(snapshot: update as! FIRDataSnapshot)
newUpdates.append(updateObject)

}

self.updates = newUpdates
self.tableView.reloadData()


}) { (error: NSError) in
print(error.description)
}
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()

}




@IBAction func addToFeed(sender: AnyObject) {
let feedAlert = UIAlertController(title: "New update", message: "Enter your update", preferredStyle: .Alert)
feedAlert.addTextFieldWithConfigurationHandler { (textField:UITextField) in
textField.placeholder = "Your update"
}
feedAlert.addAction(UIAlertAction(title: "Send", style: .Default, handler: { (action:UIAlertAction) in
if let feedContent = feedAlert.textFields?.first?.text {


if let user = FIRAuth.auth()?.currentUser {
let name = user.displayName
//let photoUrl = user.photoURL




let accessToken = FBSDKAccessToken.currentAccessToken()
if(accessToken != nil) //should be != nil
{

let req = FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"id"], tokenString: accessToken.tokenString, version: nil, HTTPMethod: "GET")
req.startWithCompletionHandler({ (connection, result, error : NSError!) -> Void in
if(error == nil)
{
let userId: String! = result.valueForKey("id") as? String!
let userID = userId
self.facebookProfileUrl = "http://graph.facebook.com/\(userID)/picture?type=large"

let likes = "0"

let feed = Sweet(content: feedContent, addedByUser: name!, profilePhoto: self.facebookProfileUrl, likesForPost: likes)
let feedRef = self.dbRef.child(feedContent.lowercaseString)

feedRef.setValue(feed.toAnyObject())




}
else
{
print("error \(error)")
}
})
}



// LAV FEEDCONTENT OM TIL OGSÅ AT MODTAGE PROFIL BILLEDE URL I STRING OG GIV SÅ facebookProfileUrl STRING LIGE HERUNDER I feed







} else {
// No user is signed in.
}
}
}))

self.presentViewController(feedAlert, animated: true, completion: nil)


}





// MARK: - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return updates.count
}


override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:updateTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! updateTableViewCell


let update = updates[indexPath.row]

//cell.textLabel?.text = update.content
//cell.detailTextLabel?.text = update.addedByUser
cell.nameLabel.text = update.addedByUser
cell.updateLabel.text = update.content
cell.likesLabel.text = "\(update.likesForPost) hi-fives"


if update.profilePhoto! != "" {
if let url = NSURL(string: update.profilePhoto!) {
if let data = NSData(contentsOfURL: url) {
cell.picView.image = UIImage(data: data)
cell.picView.layer.cornerRadius = cell.picView.frame.size.width/2
cell.picView.clipsToBounds = true

}
}
} else {
print("Empty facebookProfileUrl")
}





loadingSpinner.stopAnimating()

return cell
}


}

Answer

Modify your struct to include one more variable (lets say let path : String!)that will include the value of the node key retrieved from your DB(megaTest or test).

Your Struct

   struct Sweet {
let key: String!
let content: String!
let addedByUser: String!
let profilePhoto: String!
var likesForPost: String!
let itemRef: FIRDatabaseReference?
let path : String! 


init (content: String, addedByUser: String, profilePhoto: String!, likesForPost: String!, key: String = "",dataPath : String!) {
    self.key = key
    self.content = content
    self.addedByUser = addedByUser
    self.profilePhoto = profilePhoto
    self.likesForPost = likesForPost
    self.itemRef = nil
    self.path = dataPath
}

init (snapshot: FIRDataSnapshot) {
    key = snapshot.key
    itemRef = snapshot.ref
    path  = key 
    if let theFeedContent = snapshot.value!["content"] as? String {
        content = theFeedContent
    } else {
        content = ""
    }

    if let feedUser = snapshot.value!["addedByUser"] as? String {
        addedByUser = feedUser
    } else {
        addedByUser = ""
    }

    if let feedPhoto = snapshot.value!["profilePhoto"] as? String! {
        profilePhoto = feedPhoto
    } else {
        profilePhoto = ""
    }

    if let feedLikes = snapshot.value!["likesForPost"] as? String! {
        likesForPost = feedLikes
    } else {
        likesForPost = "0"
    }

}

func toAnyObject() -> AnyObject {
    return ["content":content, "addedByUser":addedByUser, "profilePhoto":profilePhoto!, "likesForPost":likesForPost,"pathInTheDB" : path]
    }
}

In cellForIndexPath just add this

  cell. pathDB = self.structArray![indexPath.row].path

Modify your customCell class like this

class customTableViewCell : UITableViewCell{

    var pathDB : String! //megaTest or test

     @IBAction func likeBtn(sender : UIButton!){

             //Update like's
         }
      }

For updating the value you can use either runTransactionBlock:-

 FIRDatabase.database().reference().child(pathDB).child("likesForPost").runTransactionBlock({ (likes: FIRMutableData) -> FIRTransactionResult in
      // Set value and report transaction success
        likes.value = likes.value as! Int + 1
        return FIRTransactionResult.successWithValue(likes)
      }) { (err, bl, snap) in
        if let error = error {
          print(error.localizedDescription)
        }
      }

Or observe that node with .observeSingleEventOfType, retrieve the snap and then update

let parentRef = FIRDatabase.database().reference().child(pathDB).child("likesForPost")   
parentRef.observeSingleEventOfType(.Value,withBlock : {(snap) in

 if let nOfLikes = snap.value as? Int{

          parentRef.setValue(nOfLikes+1)

    }

})