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:
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:
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.once()
method (ie ref.once('value',function(snapshot) {..}
), use the promise "flavor" (ie, with await: await ref.once('value');
).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);
}
});
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.