Count number of mutual friends in Firebase

2019-12-16 21:01发布

I'm trying to pull the number of mutual friends that I have with any given userID. I first pulled all my friends from Firebase and then I pulled the userID's friends. I'm just not sure how to count the number of mutual friends from there. Please let me know if I'm going about it the wrong way.

func fetchMutualFriends(myID: String, userID: String) {

    let myID = Auth.auth().currentUser!.uid

    let postRef = self.databaseRef.child("friends").child(myID)

    postRef.observe(.value, with: { (snapshot) in
        for childSnapshot in snapshot.children {
              print(childSnapshot)

        }
    })
    let postRef1 = self.databaseRef.child("friends").child(friendID)

    postRef1.observe(.value, with: { (snapshot) in
        for childSnapshot in snapshot.children {
            print(childSnapshot)

        }
    })
}

Firebase structure

root/
|___ friends/
|      |___ myID
|              |___ friendID1
|      |___ friendID1
|              |___ myID

3条回答
【Aperson】
2楼-- · 2019-12-16 21:44

It would help a lot if you post the structure of your database in your question.

I assume it looks something like this:

root/
|___ users/
|      |___ userID1
|              |___ name : user_name
|              |___ email : user_email
|              |___ picUrl : user_picture_url
|              |___ friends
|                       |___ userID2 : true                    
|                       |___ userID3 : true
|                        ...

I added a lot of comments in the code below to make it easier for you to see every step.

So, this is how you could write your fetchMutualFriends method:

    func fetchMutualFriends(userID: String) {

         // Use a guard statement here to make sure your current user object is not nil

        guard let currentUserID = Auth.auth().currentUser?.uid else {
             return
        }

        // Create two arrays to store the two friend lists:

        var friendListA = [String]()
        var friendListB = [String]()

        // Create a dispatch group:

        let dispatchGroup = DispatchGroup()

        // Enter the dispatch group

        dispatchGroup.enter()

        // Add the observers:

        // Depending on your database structure, you may want to adjust the references below:

        Database.database().reference().child("users").child(currentUserID).child("friends").child(userID).observeSingleEvent(of: .value, with: { [weak self] (snapshot : DataSnapshot) in

                      // Iterate through all the children:    

                      for child in snapshot.children.allObjects as! [DataSnapshot] {
                          // Add the user ID to the array:
                           self?.friendListA.append(child.key)
                      })

                      if snapshot.childrenCount == 0 {
                           // TODO: Handle the case when there is no friend in the friend list.
                      }

                     // Leave the dispatch group    

                     dispatchGroup.leave()
        })


        dispatchGroup.enter()


        Database.database().reference().child("users").child(userID).child("friends").child(currentUserID).observeSingleEvent(of: .value, with: { (snapshot : DataSnapshot) in

                     // Iterate through all the children:    

                      for child in snapshot.children.allObjects as! [DataSnapshot] {
                          // Add the user ID to the array:
                           self?.friendListB.append(child.key)
                      })

                      if snapshot.childrenCount == 0 {
                           // TODO: Handle the case when there is no friend in the friend list.
                      }

                     // Leave the dispatch group    

                     dispatchGroup.leave()
       })

      // Notify the dispatch group:

      dispatchGroup.notify(queue: DispatchQueue.main, execute: {

               // Now that both completion blocks (from your two observers) ran, you can compare the two friend lists and see if they have any friends in common:

               let commonFriendsArray  = friendListA.filter { friendListB.contains($0) }

               // Do whatever you want with the common friends list :)

        })


   }
查看更多
乱世女痞
3楼-- · 2019-12-16 21:44

You have to use numChildren() function which returns the number of child properties of a DataSnapshot. Assume we have the following data in the Database:

{
  "name": {
    "first": "Ada",
    "last": "Lovelace"
  }
}

If I want to know the number of childs of name for example :

var b = snapshot.child("name").numChildren(); // 2 ("first", "last")

If I want to know the number of childs of first for example :

var c = snapshot.child("name/first").numChildren(); // 0

Hope it will guide you.

查看更多
放我归山
4楼-- · 2019-12-16 21:52

Since the actual struture is not clear, let's assume a standard structure like this

  "users"
    "user_0"
      "friends"
        "user_1" : true,
        "user_2" : true,
        "user_3" : true
    "user_1" 
      "friends"
        "user_0" : true,
        "user_2" : true
    "user_2"
      "friends"
        "user_0" : true,
        "user_1" : true,
        "user_3" : true
    "user_3"
      "friends"
        "user_0" : true,
        "user_2" : true

As you can see, user 0 is friends with user_1, user_2 and user_3, and likewise in their nodes those users are friends with user_0.

If we want to keep this structure then finding the intersection of two users mutual friends is pretty easy.

Suppose we want to find which friends user_0 and user_2 have in common. Looking at the structure we find it's

user_1
user_3

How do we do that in code?

let user1FriendsRef = self.ref.child("users").child("user_0").child("friends")
let user2FriendsRef = self.ref.child("users").child("user_2").child("friends")

user1FriendsRef.observeSingleEvent(of: .value, with: { user1Snapshot in
    let user1FriendsArray = user1Snapshot.children.map { ($0 as! DataSnapshot).key }
    let user1FriendsSet = Set(user1FriendsArray)

    user2FriendsRef.observeSingleEvent(of: .value, with: { user2Snapshot in
        let user2FriendsArray = user2Snapshot.children.map { ($0 as! DataSnapshot).key }
        let user2FriendsSet = Set(user2FriendsArray)

        let mutualFriends = user1FriendsSet.intersection(user2FriendsSet).sorted()
        print(mutualFriends)
        print(mutualFriends.count)
    })
})

Here's how that code works: We start with a reference to the two users friends lists we want to compare

Using observeSingleEvent, the first users friends list is read and the keys (user_1, user_2 etc) are stored in an array. That is done my mapping (iterating over) each key: value pair to capture the key. That array is converted to a Set var.

We do the same thing for the second user - noting it's important we do that within the first closure so we are guaranteed the results from the first user are complete. Those results are mapped to an array and the made into a Set.

Then, the magic of leveraging the intersection function of a Set and then print the mutual friends (sorted)

["user_1", "user_3"]
2
查看更多
登录 后发表回答