简体   繁体   中英

Firebase function to get ranking

I am new to firebase and would like to implement the ranking for the players stored in the rank table from firebase real-time db, see screenshot below: 我的 Firebase 数据库排名表

I have also setup the rules for the index:

{
  "rules": {
    ".read": "auth != null",
    ".write": "auth != null",
      "TH": {
        "rank": {
        ".indexOn" : ["balance", "w_rate","match"]  
        }
      }
  }
}

in my firebase function, I have a function as a post request to get the rank:

exports.getRank = functions.https.onRequest(async (req,res) => {

    const user_id = req.query.id;
    console.log(`user_id ${user_id} `);
    const query = database().ref('TH/rank')
                    .orderByChild('balance')
                    .limitToLast(30)

    query.once('value',function(snapshot) {

        console.log('in side the usersRef');
        console.log(`snapshot:${JSON.stringify(snapshot.val())}`);

        let current_user_rank = 0;

        if (user_id !== null) {

            console.log(`user id ${user_id} isn't null`);

            database().ref('TH/rank/').orderByChild('balance').once('value',function(all_snapshot){
                let index = 0;
                console.log(`user id ${user_id} all snapshot.`);

                if (all_snapshot.child(`${user_id}`).exists()) {
                    console.log(`user id ${user_id} exists`);
                    const current_user_data = all_snapshot.child(`${user_id}`).val();
                    all_snapshot.forEach( child => {
                        index += 1;
                        console.log(child.key, child.val());
                        if(child.key === user_id) {
                            current_user_rank = all_snapshot.numChildren() - index;
                        }
                    });
                    res.json({
                        user: { id: user_id,
                                rank: current_user_rank,
                                data: current_user_data
                        },
                        rank: snapshot.val()
                    });

                } else {
                    res.json({
                        user: { id: user_id,
                                rank: current_user_rank,
                                data: null
                        },
                        rank: snapshot.val()
                    });
                }
            }).catch();

        } else {
            
            res.json({
                user: { id: user_id,
                        rank: current_user_rank,
                        data: null
                },
                rank: snapshot.val()
            });
            
        }
    }).catch();
});

However, the result isn't correct, it seems the orderByChild doesn't work at all. Can someone help on this?

Thanks.

There are several problems with your Cloud Function:

  1. You use async when declaring the callback but you never use await in the Cloud Function, in order to get the result of the asynchronous once() method.
  2. Instead of using the callback "flavor" of the once() method (ie ref.once('value',function(snapshot) {..} ), use the promise "flavor" (ie, with await: await ref.once('value'); ).
  3. The result is that you don't correctly manage the Cloud Function life cycle. For more details on how to do that correctly, I would suggest you watch the 3 videos about "JavaScript Promises" from the Firebase video series as well as read the following doc .

So the following should do the trick. (Note that I've just adapted it to correctly manage the life cycle, I've not tested the business logic).

exports.getRank = functions.https.onRequest(async (req, res) => {

    try {

        const user_id = req.query.id;
        console.log(`user_id ${user_id} `);

        let current_user_rank = 0;

        if (user_id !== null) {

            console.log(`user id ${user_id} isn't null`);

            const baseQuery = database().ref('TH/rank/').orderByChild('balance');

            const query = baseQuery.limitToLast(30);

            const snapshot = await query.once('value');

            console.log(`snapshot:${JSON.stringify(snapshot.val())}`);

            const all_snapshot = await baseQuery.once('value');

            let index = 0;
            console.log(`user id ${user_id} all snapshot.`);

            if (all_snapshot.child(`${user_id}`).exists()) {
                console.log(`user id ${user_id} exists`);
                const current_user_data = all_snapshot.child(`${user_id}`).val();
                all_snapshot.forEach(child => {
                    index += 1;
                    console.log(child.key, child.val());
                    if (child.key === user_id) {
                        current_user_rank = all_snapshot.numChildren() - index;
                    }
                });
                res.json({
                    user: {
                        id: user_id,
                        rank: current_user_rank,
                        data: current_user_data
                    },
                    rank: snapshot.val()
                });

            } else {
                res.json({
                    user: {
                        id: user_id,
                        rank: current_user_rank,
                        data: null
                    },
                    rank: snapshot.val()
                });
            }

        } else {

            res.json({
                user: {
                    id: user_id,
                    rank: current_user_rank,
                    data: null
                },
                rank: snapshot.val()
            });
        }

    } catch (error) {
        console.log(error);
        res.status(500).send(error);
    }

});

Update following your comment:

You need to use forEach() in order to get the children correctly ordered, and not snapshot.val() . snapshot.val() displays the children according to their key, exactly like they are ordered in the DB. The following adaptation of the code in your comment works correctly:

exports.getSortedRank = functions.https.onRequest(async (req, res) => {

    try {
        const obj = {};
        const baseQuery = admin.database().ref('TH/rank/').orderByChild('balance');
        const query = baseQuery.limitToLast(10);
        const snapshot = await query.once('value');
        snapshot.forEach(childSnapshot => {
            console.log(childSnapshot.val());
            obj[childSnapshot.key] = childSnapshot.val()
        });
        res.json({ rank: obj });
    } catch (error) { console.log(error); res.status(500).send(error); }
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM