Dravidian
Dravidian

Reputation: 9945

Saving Array in Firebase

I am using Firebase 3.0 as my backend, and I need to save my every user.uid in a separate child which needs to be an NSArray, and then retrieve that array using a for loop!

This is how I am saving my data: I have created a separate class for the FIRController which is handling all the storing and retrieving of database and storage.

func signUpUserWithBasicInfo(emailId : String! , password : String!, username : String!, age : String, gender : String!, backpackerType : String, info : [String : AnyObject], completionBlock : (() -> Void)){

    print("fir signup did recieve")
    FIRAuth.auth()?.createUserWithEmail(emailId, password: password, completion: {
        user,error in

        if error != nil{
            print("error encountered while backend email signup Handshake : \(error)")
            print("")
            self.delegate.firShowAlert("Error signing you up", Message: "Please check your network or this email already exist!")

        }else{
            print("uploading database")
            self.profilePictureUploading(info, completionBlock: {

                FIRControllerClass.ref.child("UserProfile").child(user!.uid).setValue([
                    "username" : username,
                    "email" : emailId,
                    "age" : age,
                    "gender" : gender,
                    "password" : password,
                    "typeOfBackpacker" : backpackerType
                    ])

                completionBlock()

            })
        }
    })
}

func profilePictureUploading(infoOnThePicture : [String : AnyObject],completionBlock : (()->Void)) {

    if let referenceUrl = infoOnThePicture[UIImagePickerControllerReferenceURL] {
        print(referenceUrl)
        let assets = PHAsset.fetchAssetsWithALAssetURLs([referenceUrl as! NSURL], options: nil)
        print(assets)
        let asset = assets.firstObject
        print(asset)
        asset?.requestContentEditingInputWithOptions(nil, completionHandler: { (ContentEditingInput, infoOfThePicture)  in

            let imageFile = ContentEditingInput?.fullSizeImageURL
            print("imagefile : \(imageFile)")

            let filePath = FIRAuth.auth()!.currentUser!.uid +  "/\(Int(NSDate.timeIntervalSinceReferenceDate() * 1000))/\(imageFile!.lastPathComponent!)"
            print("filePath : \(filePath)")

                FIRControllerClass.storageRef.child("ProfilePictures").child(filePath).putFile(imageFile!, metadata: nil, completion: { (metadata, error) in

                         if error != nil{

                            print("error in uploading image : \(error)")
                            self.delegate.firShowAlert("Error Uploading Your Profile Pic", Message: "Please check your network!")
                         }

                          else{

                                print("metadata in : \(metadata!)")
                                print(metadata?.downloadURL())
                                print("The pic has been uploaded")
                                print("download url : \(metadata?.downloadURL())")

                                self.uploadSuccess(metadata!, storagePath: filePath)

                                completionBlock()

                }

            })
        })

    } else {
            print("No reference URL found!")
    }
}

How would I create a child in my backend which would serve as array, and how can I retrieve that array?

My firebase JSON STRUCTURE : -

{
  "UserId" : [ 1, 
    "Sq5EDvVOsQWkLylEx3GrBdEsIN92",
    "xC4jCJmobUcqghq8C3SI1XT0UPk1",
    "D8QmnOSH6vRYiMujKNXngzhdn992",
    "riHjon6wknOmALwf0Z0Ri5aOMA82",
    "fKqlb88MKsYCE43xy7D51qH6jqH3",
    "aCgAFAGDIgWRSUu9a2aMo9HtnnD3",
    "iicKACGo8RaeTSEggKPB0sU2Bme2",
    "qJ2c8AcEYzVkJKLl13N92tyKnbz2"
    ],
  "UserProfile" : {
    "D8QmnOSH6vRYiMujKNXngzhdn992" : {
      "age" : "12",
      "email" : "[email protected]",
      "gender" : "f",
      "password" : "123454321",
      "typeOfBackpacker" : "dummy",
      "username" : "duummyy1"
    },
    "Sq5EDvVOsQWkLylEx3GrBdEsIN92" : {
      "age" : "121",
      "email" : "[email protected]",
      "gender" : "gjhg",
      "password" : "123454321",
      "typeOfBackpacker" : "chef",
      "username" : "hgfgh"
    },
    "aCgAFAGDIgWRSUu9a2aMo9HtnnD3" : {
      "age" : "24",
      "email" : "[email protected]",
      "gender" : "F",
      "password" : "123454321",
      "typeOfBackpacker" : "Group",
      "username" : "Cathy"
      },
      etc
}

i also need to add an array of no of friends in my database(array).The only reason i am using for loop is so that i can display every user's details to my user(apart from him/her self) using the userId array that i have created in my database, which are actually the parent node to my every respective user database.

This is how i am appending UserId in my database :-

func retrieveUserIdsArray(completionBlock : ((appendedArr : NSMutableArray) -> Void)){

    var appendedArray : NSMutableArray = []

    FIRControllerClass.ref.child("UserId").observeEventType(FIRDataEventType.Value, withBlock: {(snapshot) in

        if let userIdDetails = snapshot.value as? NSMutableArray{

        userIdDetails.addObject((FIRAuth.auth()?.currentUser?.uid)!)
        appendedArray = userIdDetails

        completionBlock(appendedArr: appendedArray)

        }
    })
} 

which is called in this function :-

    func signUpUserWithBasicInfo(emailId : String! , password : String!, username : String!, age : String, gender : String!, backpackerType : String, info : [String : AnyObject], completionBlock : (() -> Void)){

    print("fir signup did recieve")

    FIRAuth.auth()?.createUserWithEmail(emailId, password: password, completion: {
        user,error in

        if error != nil{

            print("error encountered while backend email signup Handshake : \(error)")

            print("")

            self.delegate.firShowAlert("Error signing you up", Message: "Please check your network or this email already exist!")

        }else{

            print("uploading database")

            self.profilePictureUploading(info, completionBlock: {

                FIRControllerClass.ref.child("UserProfile").child(user!.uid).setValue([
                    "username" : username,
                    "email" : emailId,
                    "age" : age,
                    "gender" : gender,
                    "password" : password,
                    "typeOfBackpacker" : backpackerType
                    ])


                var a = 0

                self.retrieveUserIdsArray({ (appendedArr) in

                    a += 1

                    print("The appended array is : \(appendedArr)")

                    if a == 1{

                        FIRControllerClass.ref.child("UserId").setValue(appendedArr)

                    }else{

                        completionBlock()

                    }
                })
            })
        }
    })
}

The reason why i have used a variable is to tackle the infinite loop which it was causing(i know its just a hack, for now ..)

Open to any better way to tackle this!..

Upvotes: 0

Views: 4152

Answers (1)

Jay
Jay

Reputation: 35648

Array's can be challenging in Firebase as the individual elements cannot be accessed directly or modified. You either read the whole array or write the whole array.

I would suggest changing the Structure to better match the data you want and avoid array's entirely:

"UserProfile" : {
    "D8QmnOSH6vRYiMujKNXngzhdn992" : {
      "age" : "12",
      "email" : "[email protected]",
      "gender" : "f",
      "password" : "123454321",
      "typeOfBackpacker" : "dummy",
      "username" : "duummyy1"
      "friend_count": 10
      "friend_of"
         "aCgAFAGDIgWRSUu9a2aMo9HtnnD3": true
    },

then a simple deep query will return everything you need (Firebase v2)

let myUid = "aCgAFAGDIgWRSUu9a2aMo9HtnnD3"
let path = ("friend_of/\(myUid)") // equals friend_of/aCgAFAGDIgWRSUu9a2aMo9HtnnD3
var userIdArray = [String]()
userProfileRef.queryOrderedByChild(path)
              .queryEqualToValue(true)
              .observeSingleEventOfType(.Value, withBlock: { snapshot in
   for child in snapshot.children {
      let userId = child.key as String
      userIdArray.append(userId)
   }
   //loop is done, now we have an array of userIds that are friends
})

The code returns every user who is a friend on mine (myUid)

I've also added a 'friend count' node that simply keeps a count of that users number of friends. When a friend is added, increment the value, when removed decrement. It's a quick

myUid.child("friend_count").setValue(updated_count)

This code also avoids loops, callbacks and additional completion blocks because it rely's on Firebase to get the data, and let us know when it's done.

If you really, really want to read an array node (not recommended)

    let myRef = self.myRootRef.child("array_node")
    myRef.observeSingleEventOfType(.Value, withBlock: { snapshot in

        let a = snapshot.value as! NSArray
        print(a) //a an NSArray

        let b = (a as Array).filter {$0 is String}

        print(b) //b is a Swift Array

        print( b[1] )
    })

Upvotes: 2

Related Questions