-1

I want to implement a follow system between users. For that, I want to display all of the 250 users of my app, then add a checkmark button next to the ones I already follow, and an empty button next to the ones I do not follow.

var usersRef = firebase.database().ref(‘/users’);
var followingRef = firebase.database().ref(‘/followingByUser’);
var displayedUsers = [];

// I loop through all users of my app
usersRef.once('value', users => {

  users.forEach(user => {     

    // For each user, I check if I already follow him or not
    followingRef.child(myUid).child(user.key).once('value', follow => {

      if (follow.val()) {

        // I do follow this user, follow button is on
        displayedUsers.push({
          name: user.val().name,
          following: true
        });

      } else {

        // I do not follow this user, follow button is off
        displayedUsers.push({
          name: user.val().name,
          following: false
        });

      }

    })
  })
})

When doing that, I often (not always) get the following error: "Error: Firebase Database (4.1.3) INTERNAL ASSERT FAILED: sendRequest call when we're not connected not allowed."


Eventually, all the data is fetched, but after 10 seconds instead of 1 (without the error). I do not believe it is an internet connection issue, as I have a very fast and stable wifi.

Is it a bad practice to nest queries like that? If not, why do I get this error?

My data is structured as below:

users: {

  userId1: {
    name: User 1,
    email: email@exemple.com,
    avatar: url.com
  },

  userId2: {
    name: User 2,
    email: email@exemple.com,
    avatar: url.com
  },

  ...
}

followByUser: {

  userId1: {
    userId2: true,
    userId10: true,
    userId223: true
  },

  userId2: {
    userId23: true,
    userId100: true,
    userId203: true
  },

  ...
}

1 Answers1

1

Your current database structure allows you to efficiently look up who each user is following. As you've found out it does not allow you to look who a user is follow by. If you also want to allow an efficient lookup of the latter, you should add additional data to your model:

followedByUser: {
  userId2: {
    userId1: true,
  }
  userId10: {
    userId1: true,
  },
  userId223: {
    userId1: true,
  },
  ...
}

This is a quite common pattern in Firebase and other NoSQL databases: you often expand your data model to allow the use-cases that your app needs.

Also see my explanation on modeling many-to-many relations and the AskFirebase video on the same topic.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thanks a lot for the quick answer. However, "it does not allow you to look who a user is follow by" is not what I am trying to achieve. I simply want to know if I am already following or not each user in the list. – Antoine Dupont Jul 10 '17 at 18:11
  • At the end of the story, I need info from both: - usersRef: name and avatar of the user - followingRef: if I follow the user or not – Antoine Dupont Jul 10 '17 at 18:18
  • Then why don't you simply attach a `value` listener to `/followingByUser/myUid/uidOfUserIWantToFollow`? Also see https://stackoverflow.com/questions/37910008/check-if-value-exists-in-firebase-db – Frank van Puffelen Jul 10 '17 at 18:22
  • But is it not what I am already doing in my example? Or should I use "orderByChild" and "EqualTo" methods for better performance? (I updated my code as it was not exactly right) – Antoine Dupont Jul 10 '17 at 18:49
  • You're looping over all followers, instead of just querying for the one that is relevant. But I feel we're going around in circles a bit, so let's take a step back: what is this code trying to accomplish (also see [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem))? One of the advantages of the structure `/followingByUser/myUid/uidOfUserIWantToFollow: true` is that you can just set it to `true` again and again when the user clicks the "follow" button, since that operation is idempotent. – Frank van Puffelen Jul 10 '17 at 19:30
  • You’re right, I’ll try to explain my problem better. The idea is to have a list of all users with a checkmark button for users I follow, and an empty button for users I do not follow. So I need to load ALL the users available on my app and then check which users I already follow. – Antoine Dupont Jul 10 '17 at 21:11
  • Let me know if my goal is more clear or not. I can give you more details if you need. I really need to know if this kind of nested queries is even recommended with firebase. As of right now, it impacts a lot my UX. – Antoine Dupont Jul 11 '17 at 12:23