0

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!..

3
  • Array's can be very challenging in Firebase (or any NoSQL database) and their use is very situational as there are usually better options to store the data. Also, reading data from Firebase in a for..loop is not a good idea as it circumvents the asynchronous nature of Firebase. Can you provide a use case for using array's in that fashion? Commented Jul 14, 2016 at 19:25
  • I want to store the id's of my users in a particular array so that i can show their details in 'Find Friends ' section!... i am saving their personal database in their unique user.uid as child to a 'UserProfile' node. i need to access all the database at once in one page, and apply geolocation algorithm and recommendation engine in other page...thats why i need have an array where i can store all my user's unique ids. Commented Jul 14, 2016 at 23:07
  • There may be a better way to do that. Can you post a sample of your Firebase structure so we can see what you have now? Please post as text, no images. You can get that via the Firebase Console->Three Dots on right->Export JSON. Commented Jul 15, 2016 at 17:00

1 Answer 1

2

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] )
    })
Sign up to request clarification or add additional context in comments.

2 Comments

let myUid = "aCgAFAGDIgWRSUu9a2aMo9HtnnD3" is something that you have hardcoded , and i need to have every user.uid to populate my tableView.That was the reason why i was storing every user's uid in an array in the first place. btw thanks fr the help!
@AchintyaGupta I hard coded that as an example uid. That would be the uid of the currently logged in user derived from the Firebase auth variable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.