0
votes

I have an Firebase structure like this:

Chatrooms {
  -efsCsTB95 {
    Messages {
      -bdre3G5 {
         Title: ...
          }
      -wer23bd {
         Title: ...
          }
     }
   }
}

I have a view like this:

<div class="card" ng-repeat="list in chatrooms">
    <div class="item item-positive item-text-wrap">
        {{list.videoTitle}}
    </div>
    <div class="item item-stable">
        <div class="card-footer text-right">
            <i class="icon ion-chatbox-working positive"></i>
            <b class="positive">{{list.messageCount}}</b>
        </div>
    </div>
</div>

The list.messageCount try to get the length of the messages node inside the firebaseAarry chatrooms. The message length will be updated when there are more messages inside the room page. Since I cannot get the length of a nested array inside a firebaseArray like list.messages.length, I loop the chatrooms array in side my controller like this:

$scope.chatrooms = $firebaseArray($scope.chatroomsRef);

    $scope.chatrooms.$loaded()
    .then(function(){
        angular.forEach($scope.chatrooms, function(room, key) {
            var messagesRef = $rootScope.baseUrl + "chatrooms/" + room.$id + "/messages/";
            console.log (messagesRef);
            var messagesNode = $firebaseArray(new Firebase(messagesRef));
            messagesNode.$loaded().then(function(){
                console.log (messagesNode.length);
                $scope.chatrooms[key].messageCount = messagesNode.length;
            });
            $scope.chatrooms.$watch(function() {
                messagesNode.$loaded().then(function(){
                    console.log (messagesNode.length);
                    $scope.chatrooms[key].messageCount = messagesNode.length;
                });
            });
        });
    });

In each loop, I open up another $firebaseArray connection called messagesNode. And I wait till the messagesNode loaded with $loaded, and give it to a new local attribute called messageCount, attached to each room. When there are more messages added to the room, I use $watch to re-get the length and re-attach it to messageCount.

So this solution work. The list.messageCount has live update (2-way binding). BUT, is this the correct solution?! It just seem too much work to just get the length of a array object inside a firebaseArray. If I just use

$scope.chatroomsRef.on('child_added', function(snapshot){

        var snapshotVal = snapshot.val();
        var messageCount = snapshot.child('messages').numChildren(); });

The messageCount is always updated. It just seem strange the $firebaseArray actually make thing way difficult to do instead of providing helper function like "numChildren()"?! Firebase Expert, please advice the best way to do this kind of simple task.

1
Yikes. Are you really loading all messages in each client to show a count? Sounds like a great way to burn through your bandwidth quota as you get more users. In general I recommend against displaying counts in NoSQL applications, since counters are a tricky concept to keep in sync as your number of users grows. But if you insist on showing a count, store the message count somewhere in your Firebase and use transaction calls to update it. At least that way the "counters are a tricky concept to keep in sync" problem will only hurt on writes and not for every read operation. - Frank van Puffelen
@FrankvanPuffelen Great suggestion. I am a total noSQL noob. I took your suggestion to use transaction to post store the counter. BTW, is there a good way to monitor the transnational usage of my application so I can minimize all the necessary bandwidth and improve the code? Since this is not an error...and it is really hard to figure out this performance bugs...Any best practise will be greatly appreciated! - Hugh Hou
Also, by storing the counter number instead of dynamically calculating it using another firebaseObject. Is that following the principle: "Essentially, we are optimizing our data reads by writing extra data at write-time. Consider that disk space is cheap, but a user’s time is not." quote in here:firebase.com/blog/2013-04-12-denormalizing-is-normal.html - Hugh Hou

1 Answers

1
votes

Taking @FrankvanPuffelen suggestion, I think he is absolutely right (I am a Firebase and NoSQL noob). Each time a user post a message, I can see console logged TWICE of this line: console.log (messagesNode.length); And this is to every chatroom!! A lot of read quotes.

So I do need the comment count. So the solution is, each time user comment, I add this code:

roomRef.child("messageCounter").transaction(function(Counter) {
                    return Counter+1;
                });

Using transaction to update the counter and store it onto the Chatroom node. So in the view, I just replace {{list.messageCount}} to {{list.messageCounter}}, which is a node under the chatroom. No need to count comment and more.

I will also love to learn more about Firebase quotes and more best practise to avoid burning tho them. Like when to close a firebaseAarry after it is done... I think this is a missing manual for firebase.