将参数从 Google Cloud 函数 GET 请求传递到 BigQuery

Posted

技术标签:

【中文标题】将参数从 Google Cloud 函数 GET 请求传递到 BigQuery【英文标题】:Passing params from a Google Cloud Function GET Request to BigQuery 【发布时间】:2020-06-02 15:49:48 【问题描述】:

我已经成功部署了一个谷歌云函数,它接收来自 POST 请求的参数。我现在正在尝试将其更改为从 GET 请求中获取参数,因为参数不包含任何私有数据。

似乎我正确地获取了传入的参数,但是当我尝试将它们传递给 bigQuery 时,它告诉我我的查询缺少参数。我知道我的代码是正确的,因为如果我对参数的值进行硬编码,它可以正常工作,例如:

bigQuery.createQueryJob(
    query,
    params: 
    "make": "acura",
    "model": "mdx",
    "modelYear": 2005

).then...

我也知道我得到了正确的参数,因为如果我将我的云函数更改为只返回传入的查询字符串参数,它会正确返回它们(下面注释掉的行)。如果我将云功能更改为使用 req.body 而不是 req.query 并使其成为 POST 请求,它也可以正常工作。

我不知道为什么“参数”没有正确传递给 createQueryJob。任何帮助将非常感激。这是代码(出于隐私原因,我不得不删除实际查询):

package.json:


    "name": "sample-http",
    "version": "0.0.1",
    "dependencies": 
        "@google-cloud/bigquery": "^2.0.6"
    

index.js:

const  BigQuery  = require("@google-cloud/bigquery");

/**
 * Responds to any HTTP request.
 *
 * @param !express:Request req HTTP request context.
 * @param !express:Response res HTTP response context.
 */
exports.getRecallDataByVehicleInfo = (req, res) => 
    res.set('Access-Control-Allow-Origin', "*");
    res.set('Access-Control-Allow-Methods', 'GET, POST');
    res.setHeader(
        "Access-Control-Allow-Headers",
        "X-Requested-With,content-type"
    );

    const params = req.query;
   // res.status(200).send("make is - " + params.make + ", model is - " + params.model + ", model year is -" + params.modelYear);
   // return;

    const bigQuery = new BigQuery();

    const query = `myQuery
        where Make = @make
        and Model = @model
        and ModelYear = @modelYear`

    bigQuery.createQueryJob(
        query,
        params
    ).then(results => 
        const job = results[0];
        return job.getQueryResults(
            autoPaginate: false,
            timeoutMs: 1000000
        , 
        callback());
    );

    const callback = () => (err, rows) => 
        if (err) 
            res.status(401).send(JSON.stringify(err));
        
        else 
            res.status(200).send(rows);
        
    ;

【问题讨论】:

如果您的问题有更新,您可以使用底部的编辑链接对其进行编辑。无需添加评论。 @MykWillis 感谢您的回复!我不确定你是什么意思。你可能想参考这个cloud.google.com/bigquery/docs/parameterized-queries @PaulFabbroni 啊,很明显! 【参考方案1】:

你没有使用正确的方法。看看createQueryJob definition

没有参数,它用于将查询创建为作业。如果您查看the official (bad) example,则必须使用query 方法。这里its definition

注意:为什么这个例子不好?

在官方示例中,提供给query方法的参数命名为option。在query 方法的文档中,第一个(也是必需的)参数命名为query,您可以选择添加option 参数。所以,命名很混乱。

【讨论】:

嗯,根据您是对的文档。但是,我一直都是这样做的,它工作得很好,当我对参数进行硬编码时,它仍然可以作为 POST 或 GET 正常工作。我有一种感觉,他们更改了功能/文档,这将解释令人困惑的命名约定以及为什么我的代码仍然有效(可能向后兼容但未记录)。话虽如此,我将其更改为使用 query 而不是 createQueryJob 就像您说的那样,它现在似乎正在工作。非常感谢! 刚刚意识到我在 package.json (2.0.6) 中使用了一个非常旧的版本,最新的是 4.7.0,所以它可能是它的一部分,尽管我再次使用的是 4.7。 0 在另一个项目和 createQueryJob 与上面相同,它作为一个帖子工作正常,所以我不确定发生了什么,但我会继续这样做。 看起来谷歌的 createQueryJob 代码确实可以处理参数,即使它没有记录,这可以解释为什么我的代码通常可以工作github.com/googleapis/nodejs-bigquery/blob/master/src/…【参考方案2】:

感谢@guillaume blaquiere 的帮助!我将代码更改为以下内容,它现在似乎可以工作了:

const  BigQuery  = require("@google-cloud/bigquery");

/**
 * Responds to any HTTP request.
 *
 * @param !express:Request req HTTP request context.
 * @param !express:Response res HTTP response context.
 */
exports.getRecallDataByVehicleInfoTest = (req, res) => 
    res.set('Access-Control-Allow-Origin', "*");
    res.set('Access-Control-Allow-Methods', 'GET, POST');
    res.setHeader(
        "Access-Control-Allow-Headers",
        "X-Requested-With,content-type"
    );

    const params = req.query;
    const query = `query
        where lower(Make) = @make
        and lower(Model) = @model
        and CAST(ModelYear as String) = @modelYear`

    const queryObj = query, params;
    const options = 
        autoPaginate: false,
        timeoutMs: 1000000
    

    const bigQuery = new BigQuery();
    bigQuery.query(queryObj, options, function(err, rows)
        if (err) 
            res.status(401).send(JSON.stringify(err));
        
        else 
            res.status(200).send(rows);
        
    );

更新

问题不是我使用旧包或我使用 createQueryJob 而不是查询。 POST 可以工作的原因以及硬编码参数可以工作的原因是因为它们可以正确地将 modelYear 作为数字发送。但是,当您从 queryString modelYear 获取参数时(显然)以字符串形式出现,这会破坏 where 子句中的 bigQuery sql 比较。

用于测试云功能的 UI 假定一个 POST 请求,因此它会告诉我我没有传入 make 参数,而浏览器中的实际调用只会出错而没有有用的错误消息,因为我没有正确捕获并返回错误,因为我只是在我的 createQueryJob 上执行了 .then 而不是 .catch。所以我不知道真正的问题是什么。

底线 - createQueryJob 和 query 都可以接受参数,尽管文档仅显示它用于查询,并且云函数的 GET 和 POST 在处理将参数传递给这些函数的方式方面没有区别。

这里是显示 createQueryJob 也处理参数的代码: https://github.com/googleapis/nodejs-bigquery/blob/master/src/bigquery.ts#L1139

【讨论】:

请使用您问题上的编辑链接添加其他信息。 Post Answer 按钮应仅用于问题的完整答案。 - From Review @camelccc - 抱歉,谢谢,我已更新并要求删除另一个

以上是关于将参数从 Google Cloud 函数 GET 请求传递到 BigQuery的主要内容,如果未能解决你的问题,请参考以下文章

如何从 google.cloud.monitoring_v3 将参数传递给 list_time_series 方法?

我如何将变量传递给Google Cloud函数

TableRow.get上的Google Cloud Dataflow,BigQueryIO和NullPointerException

如何从 google-cloud-platform vminstance 中的 pubsub 回调函数调用全局变量?

使用 HttpRequest 作为 payload_type 时,Google Cloud Tasks 始终将 HttpMethod 设置为 GET

Google Cloud Function - ImportError:无法从“google.cloud”(未知位置)导入名称“pubsub”