3

下面是我用来为从 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
            })
        }
    });
});

这将返回一个函数超时,但是,当我尝试使用 获取前 n 个数据firstnquery时,它会按预期返回前 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
            })
        }
    });
});
4

1 回答 1

1

在查询中同时使用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)

我强烈建议您查看有关在实时数据库上实现分页的其他一些问题,因为那里也有一些很好的示例和解释。

于 2021-02-06T16:09:09.707 回答