3

My recyclerview gets data from json api and populate list of articles. I have now implemented a commenting system with the help of firebase realtime database. I want to show number of comments below each article image in recyclerview. I tried several methods to implement that but all of them are not very effective.

  1. At first I implemented database query based on article unique id for each view but since recyclerview has over 100 articles so it was making over 100 instance calls to database and was causing huge bandwidth problem.

  2. Then I made one query to get all comments count from database and saved them locally in SQLite database and inside recyclerview i query SQLite databse to get comments counts but inserting 100 rows with article id and comments count in SQLite is slow.

What do you guys recommend best method for such task where I will spend least amount of bandwidth and get comment counts also?

My db structure is like this.

enter image description here

get comments method

public void getComments() {
    keyrf = FirebaseDatabase.getInstance().getReference().child("Keys");
    keyrf.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            HashMap map = new HashMap();
            for( DataSnapshot child : dataSnapshot.getChildren() ) {
                String childKey = child.getKey();
                String c = child.child("c").getValue().toString();

                map.put(childKey, c);
                addComments(MainActivity.this, childKey, c);
            }
        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {

        }
    });
}

insert comments method

public static void addComments(Context context, String childKey, String c) {
    try {
        SQLiteDatabase myDB = context.openOrCreateDatabase("MyDb", Context.MODE_PRIVATE, null);

        myDB.execSQL("CREATE TABLE IF NOT EXISTS comments (articleId INTEGER not null unique, comment INTEGER not null)");
        String sql = "REPLACE INTO comments (articleId, comment) VALUES (?, ?)";
        SQLiteStatement statement = myDB.compileStatement(sql);
        statement.bindString(1, childKey);
        statement.bindString(2, c);
        statement.execute();
    } catch (Exception e) {
    }
}

1 Answers1

1

What do you guys recommend best method for such task where I will spend least amount of bandwidth and get comment counts also?

The workaround here is to keep a count property somewhere in the database and update that whenever you add/delete child nodes.

So you can consider using a new section that might look similar to this:

Fireabase-root
   |
   --- numberOfComments
          |
          --- commentId: 12
          |
          --- commentId: 10
          |
          --- commentId: 20

So everytime you add or delete a post, increase / decrease that count by one. And because the number of comments might be updated in an multi user environment, I recommend you to use FirebaseTransactions as explained my answer from this post.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • I have already done that. My question is how to get those counts so that I consume least amount of bandwidth and db connections. – Abhinav Srivastava Nov 09 '18 at 14:50
  • In this way. Not by querying or storing in a SQLite database, just by incrementing a counter once a child is deleted or added. You'll consume the minimum amount of bandwidth and db connections. So to get the counter, only one request is needed. – Alex Mamo Nov 09 '18 at 14:52
  • Exactly that's the problem, when the list has 100 articles then it queries firebase 100 times and that results in too much bandwidth. – Abhinav Srivastava Nov 09 '18 at 15:32
  • No, it's **not** true. There is no query in this case. You aren't querying anything, you just increase or decrease a number once a comment to an articole is added/deleted. If you need to display the number of comments, you create only a database call to read a number, which can be `12`, `10` or even `1000`. You don't query your database becuase you aren't counting anything. The number is already there. Is it clear now? – Alex Mamo Nov 09 '18 at 15:38
  • I checked in firebase profiler, everytime I call the database to read comments counts of an article, it shows one connection, so in a list of 100 articles, I get 100 connections to firebase only to read and display comment count of each article. These 100 connections cause over 100 kbs of extra bandwidth. – Abhinav Srivastava Nov 09 '18 at 16:25
  • That's correct because you are counting everytime 100 articles. You are looping using `getChildren()` method, which is what is does. In my solution above, you don't need to count anything, you are just displaying a simple number. That's it. To solve this, attach a listener on `db.child("numberOfComments").child(commentId)`. and get the corresponding number, right? – Alex Mamo Nov 09 '18 at 16:28
  • this is what I am using - Query mQuery = mDatabase.child(articleID); mQuery.addListenerForSingleValueEvent(new ValueEventListener()... String commentCount = dataSnapshot.child("c").getValue().toString(); And this code is inside recycler adapter and everytime i scroll recyclerview and a new view is generated, new connections to database are made and that increase bandwidth dramatically. – Abhinav Srivastava Nov 09 '18 at 16:42
  • In this case, add the number of comments within the `post` object and everytime you create another view, just get the data from inside that object without creating another database connection, right? So do not store the number in another place, to create another database call, just add it under the corresponding post object. Is it ok now? – Alex Mamo Nov 09 '18 at 16:50
  • That's the problem, I am not getting post data from firebase. post data is coming from a json api from a different server fetched by retrofit library. Only commenting system is linked with firebase. – Abhinav Srivastava Nov 09 '18 at 16:55
  • Also suppose I have 200 articles in a list and only 10 of them have comments, still every article view makes a connection to db and I get over 200 connections with null result and they result in a lot of bandwidth. – Abhinav Srivastava Nov 09 '18 at 17:05
  • In this case you should consider unify your servers. You cannot get data from another server witout creating a connection, right? Try to use only one, let's say Firebase. – Alex Mamo Nov 09 '18 at 17:07
  • If I shift posts system to firebase then that will result in even more bandwidth problem as data transfer will increase dramatically because each post has image url, a title and a description text too. However If I make just one connection to get all comments count and store all comment counts in a hashmap or arraylist, then bandwidth reduces dramatically, from 200 kbs to just 1 or 2 kbs as comment count for each article is not more than 2 bytes. And not every article has comments in the first place. i thought may be there is someother method too about which, i am not aware. – Abhinav Srivastava Nov 09 '18 at 17:11
  • Yes, you can get the entire object from a step higher, let's say the entire `numberOfComments` object and store it in a `HashMap` and then verify if the id of the post exists within that map but if you want to get them individually, you need to make a separate database call for each post. But in this case, be aware that everytime something changes in this tree, you are downloading the entire object and not just a simple number, right? As far as I know there no other method regrading this. – Alex Mamo Nov 09 '18 at 17:17
  • Okay so I guess the best option is to download entire numberofcomments object in one connection with just onetime value listener, I don't need to show comment counts updated by the second. if I make one connection for every single article id then bandwidth becomes over 200kbs. however donloading all in one connection costs only 1 or 2 kbs at max. – Abhinav Srivastava Nov 09 '18 at 17:27
  • It's good then, if don't need to data in realtime go ahead this way. Cheers! – Alex Mamo Nov 09 '18 at 17:59