firebase管理员无法查询大项

时间:2017-10-01 07:19:24

标签: firebase firebase-realtime-database google-cloud-functions firebase-admin

使用firebase admin从云功能中的集合中检索数据对于大型项目失败。我用来查询云功能选择的示例代码如下

admin.database().orderByChild('mmyyyy').equalTo(month).once('value');

当我尝试检索10600个项目(试图找出原因)时,此调用失败。在谷歌控制台中有这个日志,但没有任何其他可以指向我正确的方向

textPayload:  "Function execution took 18547 ms, finished with status: 'response error'"   

尝试失败后,我决定尝试使用firebase sdk在客户端上执行此调用,如下所示:

result = await firebase.database().ref(`transactions`).orderByChild('mmyyyy').equalTo(month).once('value');

这在客户端上运行完美,没有错误,并返回我的所有项目17000(这个json的大小是26MB)。

为什么会这样?是否有任何未记录的限制?

注意: 我将云功能内存增加到1GB,超时到5分钟,没有帮助。

以下是完整的示例代码



const admin = require('firebase-admin');
var functions = require('firebase-functions');
admin.initializeApp(functions.config().firebase);

const cors = require('cors')({
    "origin": "*",
    "methods": "POST,GET",
    "allowedHeaders": "Content-Type,uid,agence,month,course,raceType,raceNumber,status",
    "preflightContinue": false,
    "optionsSuccessStatus": 204
});

function _findTransactions(agence, month, course, raceType, raceNumber, status) {
    return new Promise((resolve, reject) => {
        try {
            let db = admin.database();

            let findPromise = db.ref(`transactions`).orderByChild('mmyyyy').equalTo(month).once('value');

            findPromise.then((result) => {

                let transactions = result.val();

                //removed business logic

                resolve(transactions);
            }).catch((err) => {
                console.log(err);
                reject(err);
            });
        } catch (error) {
            console.log(error);
            reject(error);
        }
    });
}

exports.findTransactions = functions.https.onRequest((req, res) => {
    let uid;
    try {
        cors(req, res, () => {
            uid = req.headers.uid;
            let agence = req.headers.agence;
            let month = req.headers.month;
            let course = req.headers.course;
            let raceType = req.headers.raceType;
            let raceNumber = req.headers.raceNumber;
            let status = req.headers.status;

            if (req.method !== 'GET') {
                return handleResponse(req, res, 403);
            }

            if (!uid || uid == null || uid == undefined) {
                return handleResponse(req, res, 401);
            }

            _validateUserId(uid, ['central_cashier', 'admin'])
                .then(() => {
                    _findTransactions(agence, month, course, raceType, raceNumber, status)
                        .then((result) => {
                            return handleResponse(req, res, 200, result);
                        }).catch((error) => {
                            return handleResponse(req, res, 500);
                        });
                }).catch((error) => {
                    return handleResponse(req, res, 401);
                });
        });
    } catch (error) {
        return handleError(res, uid, error);
    }
});




2 个答案:

答案 0 :(得分:2)

您的有效负载过大,如您所述exceeding the quota for Google Cloud Functions

想到两个选择:

  • 压缩有效负载。在将文件发送给客户端之前,先对文件进行Gzip处理。使用内置在Zlib模块;
  • 中的NodeJS,这很容易
  • 设置虚拟机。虚拟机不受这些限制。

答案 1 :(得分:1)

我进行了一些测试,得出的结论是,当查询产生大量结果(例如,许多数据存储区实体)时,Google Cloud Functions(GCF)正在执行某种超时或“中止”操作。有关某些背景,请参阅我对此问题的评论。

tl; dr我创建了自己的Express.js网络服务器,并在其上运行了我的GCF代码。

这是我的测试方式:我创建了一个使用http / https和Datastore API启用的ubuntu实例。在我的实例上,我安装了Node,Express,并运行了基本的https服务器(自签名证书运行良好,因为这只是测试api后端服务)。然后,我将我的GCF代码(在GCF中失败的功能)复制粘贴到我的最小Express网络服务器中。我指出我的React应用程序使用我的实例,该实例触发了一个查询,该查询导致了超过32,000个Datastore实体。我的GCF函数使用常见的datastore.runQuery()发送查询。

花了大约一分钟,但最终所有32,000个实体都由Express提供服务,并没有错误地加载到React应用程序(浏览器)中。

一条基本的Express路由调用了我的GCF函数:

app.post('/foo', (req, res) => {
  myCloudFunction(req, res);
})

const myCloudFunction = (req, res) => {
  // Inspects req, queries Datastore, and returns the results.
};

对于此测试,我的React应用仅指向https://mydomain.example.com:3000/foo (因为我的Express服务器侦听端口3000)。

因此,除非我向应用程序添加分页功能(路线图上),否则GCF似乎对我的应用程序还不够好。