0

I am building a quiz app using Flutter and Firebase Firestore. I want to display the rank of the current user in the app. So, I am getting all the user docs in descending order of their respective scores. Now from this list of docs I want the index of the current user's document, which is also the rank of the user.

I am getting all the docs in descending order of their scores like this :

final Stream<QuerySnapshot> _usersStream = FirebaseFirestore.instance
    .collection('users')
    .orderBy('totalScore', descending: true)
    .snapshots();

Now how do I get the index of the current user's document present in the list of all docs retrieved? I want to use Streambuilder to display the rank.

This is my Firestore database:

enter image description here

UPDATE:

So I tried iterating the fetched documents to get the index where uid is equal to the document's name.

First I have defined a method foorloop()

forloop(
int rank,
var data,
String? uid,
) async {
for (int i = 0; i < data.length; i++) {
if (uid == data[i].toString()) {
  rank = i;
}
}
return rank;
}

This method takes 'data' which is the list of docs from firestore fetched in descending order of scores, and 'uid' which is the current user uid. It iterates the list and returns 'rank' which is the index where uid is equal to the document name.

I called this method in a Text Widget to display the rank but it displays a text which says "Instance of 'Future'". I need it to display the expected index. How do I solve this?

StreamBuilder<QuerySnapshot>(
stream: _usersStream,
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return const Text('Something went wrong');
}

if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(
       color: Colors.deepPurple,
       ),
       );
     }

var data = snapshot.data!.docs;
int rank = 0; 

return Text(
forloop(rank, data, uid).toString()
);
},
Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
Prudhvi
  • 116
  • 3
  • 15
  • 2
    You're doing it the right way. Once you've queried the documents using the **orderBy('totalScore')** and then **descending** true, that's it - the index is in the order in which you get it from top to bottom, just loop through it and get the index of the iteration. There's nothing more to it. – Roman Jaquez Mar 05 '22 at 01:52
  • Sounds like an answer @RomanJaquez :) Also see https://stackoverflow.com/questions/46720997/leaderboard-ranking-with-firebase – Frank van Puffelen Mar 05 '22 at 02:08
  • @RomanJaquez `var data = snapshot.data!.docs; int rank = 0; for (int i = 0; i < data.length; i++) { if (uid == data[i].toString()) { rank = i; }` What am I doing wrong here? I am confused with the data types. This code isn't working, it return 0. – Prudhvi Mar 05 '22 at 02:49
  • Your code should be added to the question along with a description of what's not working the way you expect. Read: https://stackoverflow.com/help/minimal-reproducible-example – Doug Stevenson Mar 05 '22 at 03:11
  • "it doesn't work" isn't enough debugging information. Please read the link I provided again and explain in detail what specifically doesn't work the way you expect, along with your debugging information. – Doug Stevenson Mar 05 '22 at 03:39
  • @DougStevenson Is it better now? Actually I am not sure how to approach the problem. I just tried what the first comment said, so I am not sure how to explain it. Hope the question is clearer now. – Prudhvi Mar 05 '22 at 04:16

1 Answers1

2

So I finally got it.

I defined a method getRank which iterates the document list and returns the index where document id is equal to the uid of current user. Before I was using data[i] in the if condition instead of data[i].reference.id which gives the document id.

getRank(
int rank,
var data,
String? uid,
) {
for (int i = 0; i < data.length; i++) {
if (uid == data[i].reference.id) {
  rank = i + 1;
}
}
return rank;
}

Now I used this method in Streambuilder

StreamBuilder<QuerySnapshot>(
  stream: stream,
  builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
    if (snapshot.hasError) {
      return const Text('Something went wrong');
    }

    if (snapshot.connectionState == ConnectionState.waiting) {
      return const Center(
        child: CircularProgressIndicator(
          color: Colors.deepPurple,
        ),
      );
    }

    var data = snapshot.data!.docs;
    int rank = 0;

    return Text(
      getRank(rank, data, uid).toString(),
      
    );
  },
);

Here stream is :

final Stream<QuerySnapshot> stream = FirebaseFirestore.instance
    .collection('users')
    .orderBy('totalScore', descending: true)
    .snapshots();
Prudhvi
  • 116
  • 3
  • 15