下面是我用来为从firebase实时数据库检索的数据实现分页的代码。基本上,我试图根据页码获得前n个内容,然后从第一个查询中检索到的数据中获得最后n个内容。
function getUserSnapshotOrVerifyUserId(username, idToken, cb) {
if (username == null || username.length == 0 || idToken == null || idToken.length == 0)
return cb({
status: "error",
errorMessage: "Missing params."
}, null);
admin.auth().verifyIdToken(idToken).then(decodedToken => {
let uid = decodedToken.uid;
admin.database().ref().child("users").orderByChild("username").equalTo(username).once('value', snapshot => {
if (!snapshot.exists())
return cb({
status: "error",
message: "invalid-profile"
});
snapshot.forEach(child => {
const id = child.val().id;
if (id !== uid)
return cb({
status: "error",
message: "Invalid ID"
});
admin.database().ref("users/" + id).once("value", snapshot => {
if (!snapshot.exists())
return cb({
status: "error",
errorMessage: "user not found."
});
return cb(null, id, snapshot);
});
});
});
}).catch(err => cb({
status: "error",
message: err
}));
}
exports.getUserContentTestPagination = functions.https.onRequest((req, res) => {
corsHandler(req, res, async () => {
try {
const username = req.body.username || req.query.username;
const idToken = req.body.idToken;
const limit = 2;
const page = req.body.page || 1;
const limitToFirst = page * limit;
const limitToLast = limit;
getUserSnapshotOrVerifyUserId(username, idToken, async (err, id) => {
if(err) return res.json(err);
const uploadsRef = admin.database().ref('uploads').orderByChild('createdBy').equalTo(id)
const firstnquery = uploadsRef.limitToFirst(limitToFirst);
const lastnquery = firstnquery.limitToLast(limitToLast);
lastnquery.once("value", snapshot => {
res.json({
snapshot
})
})
})
} catch (err) {
res.json({
status: "error",
message: err
})
}
});
});
这将返回一个函数超时,但是,当我尝试使用firstnquery
获取前n个数据时,它将按预期返回前n个数据。问题是lastnquery
。如有任何帮助,不胜感激。
更新1:
exports.getUserContentTestPagination = functions.https.onRequest((req, res) => {
corsHandler(req, res, async () => {
try {
const username = req.body.username || req.query.username;
const idToken = req.body.idToken;
const limit = 2;
const page = req.body.page || 1;
let lastKnownKeyValue = null;
getUserSnapshotOrVerifyUserId(username, idToken, async (err, id) => {
if(err) return res.json(err);
const uploadsRef = admin.database().ref('uploads');
const pageQuery = uploadsRef.orderByChild('createdBy').equalTo(id).limitToFirst(limit);
pageQuery.once('value', snapshot => {
snapshot.forEach(childSnapshot => {
lastKnownKeyValue = childSnapshot.key;
});
if(page === 1){
res.json({
childSnapshot
})
} else {
const nextQuery = uploadsRef.orderByChild('createdBy').equalTo(id).startAt(lastKnownKeyValue).limitToFirst(limit);
nextQuery.once("value", nextSnapshot => {
nextSnapshot.forEach(nextChildSnapshot => {
res.json({
nextChildSnapshot
})
})
})
}
});
})
} catch (err) {
res.json({
status: "error",
message: err
})
}
});
});
在查询中同时使用limitToFirst
和limitToLast
是非常罕见的。事实上,我很惊讶这没有引发错误:
const firstnquery = uploadsRef.limitToFirst(limitToFirst);
const lastnquery = firstnquery.limitToLast(limitToLast);
Firebase查询基于游标。这意味着要获取下一页的数据,您必须知道上一页上的最后一项。这与大多数基于偏移量的数据库不同。Firebase不支持基于偏移量的查询,所以你需要知道createdBy
的值和上一页最后一项的键。
有了这个,你可以得到下一页的项目:
admin.database().ref('uploads')
.orderByChild('createdBy')
.startAt(idOfLastItemOfPreviousPage, keyOfLastItemOfPreviousPage)
.limitToFist(pageSize + 1)
我强烈建议查看一下关于在实时数据库上实现分页的其他一些问题,因为那里也有一些很好的示例和解释。