测试云功能 - 无法读取未定义的 属性 'data'

Testing Cloud Function - Cannot read property 'data' of undefined

我有一个 Raspberry Pi 并设置了一个天气(和土壤湿度)装置。

我找到了这个指南:https://codelabs.developers.google.com/codelabs/iot-data-pipeline 我按照它进行了操作,但在第 6-7 步时卡住了。

据我了解 - 当我向 PubSub 发送数据时 - 没有任何反应。在 Raspberry End 上,我有点觉得数据正在发送,但没有传递到 BigQuery。我在不同的点做了一些打印语句,试图看看它卡在哪里。

当我试图找出错误时,我慢慢回溯到第 5 步(创建云函数)。 可以在这里看到第 5 步以及我复制的相关代码:https://codelabs.developers.google.com/codelabs/iot-data-pipeline/#4

在 GCP 中 - 我点击云功能 -> function-weatherPubSubToBQ -> 测试(选项卡)

在标题下 - 触发事件 - 我填写了下面的JSON:

{
 "sensorID":"Raspberry", 
 "timecollected":"2020-09-11 06:45:19", 
 "zipcode":"00000", 
 "latitude":"0.0", 
 "longitude":"0.0", 
 "temperature":"-273", 
 "humidity":"-1", 
 "dewpoint":"-273", 
 "pressure":"0"
}

当我点击 - 测试功能 - 输出如下

**Error: function execution failed. Details:
Cannot read property 'data' of undefined**

Screen capture of JSON and error message

我猜是这两件事之一导致了问题。 event.dataPubSubMessage.data

我尝试对代码进行一些更改,但我只是在黑暗中拍摄。

我想知道是否:

  1. 我做错了什么,这意味着可能还有其他的 其他地方的问题。
  2. 这个指南有点老了,有 进行了一些更新,使指南中的旧代码不再 根据需要发挥作用。 (不是指南中的 step/image 匹配什么 我在网上看到,截至 2020 年 9 月)
  3. 如果有人知道哪里出了问题 代码并能够让我知道如何解决它 非常感谢。

提前致谢。

TLDR:该教程已过时,不要使用它,除非你想面对多个问题并想在困难中学习

我完成了教程并且能够重现这个问题..等等。正如您已经提到的那样,教程已经过时并且很多东西都发生了变化,您可以通过查看图像并注意到 UI 甚至有所不同来推断,所以我不会向任何人推荐本教程GCP 新手。

第一期:

**Error: function execution failed. Details: Cannot read property 'data' of undefined**

可以通过查看 pub/sub 消息中预期的 structure 轻松解决:

{
  "data": string,
  "attributes": {
    string: string,
    ...
  },
  "messageId": string,
  "publishTime": string,
  "orderingKey": string
}

这么简单吧?然而,一旦你像我一样用自己的变量模仿消息的结构:

{
    "data": "",
    "attributes": {
        "sensorID":"Raspberry", 
        "timecollected":"2020-09-11 06:45:19", 
        "zipcode":"00000", 
        "latitude":"0.0", 
        "longitude":"0.0", 
        "temperature":"-273", 
        "humidity":"-1", 
        "dewpoint":"-273", 
        "pressure":"0"
    },
    "messageId": "id_1",
    "publishTime": "2014-10-02T15:01:23Z",
    "orderingKey": ""
}

您将收到关于 JSON:

的错误
SyntaxError: Unexpected token ' in JSON at position 1

这个错误是由于在变量incomingData内部构造JSON时使用了'所以你必须改变第一个变量声明,我通过使用模板文字:

const incomingData = PubSubMessage.data ? Buffer.from(PubSubMessage.data, 'base64').toString() : `{"sensorID": "na","timecollected":"01/01/1970 00:00:00","zipcode":"00000","latitude":"0.0","longitude":"0.0","temperature":"-273","humidity":"-1","dewpoint":"-273","pressure":"0"}`;

但是问题还没有结束,在尝试插入 BigQuery 时进行了一些测试后,我收到了有关插入的错误,但不知道到底发生了什么,所以我隔离了在外部脚本中咨询,发现 错误处理是错误的 ,我建议您首先更改的是 package.json 中的 BigQuery 版本,来自:

"@google-cloud/bigquery": "^0.9.6"

进入

"@google-cloud/bigquery": "5.2.0"

这是撰写此答案时的最新版本。下一部分是将您使用 BigQuery 构造函数的方式重新定义为:

const bigquery = new BigQuery({
    projectId: projectId
  });

然后经过多次测试,我发现 catch 没有按预期完成它的工作,因此必须将那部分重写为:

  bigquery
    .dataset(datasetId)
    .table(tableId)
    .insert(rows)
    .then((foundErrors) => {
      rows.forEach((row) => console.log('Inserted: ', row));
      if (foundErrors && foundErrors.insertErrors != undefined) {
        foundErrors.forEach((err) => {
            console.log('Error: ', err);
        })
      }
    })
    .catch((err) => {
      bigquery
    .dataset(datasetId)
    .table(tableId)
    .insert(rows)
    .then((foundErrors) => {
      rows.forEach((row) => console.log('Inserted: ', row));

      if (foundErrors && foundErrors.insertErrors != undefined) {
        foundErrors.forEach((err) => {
            console.log('Error: ', err);
        })
      }
    })
    .catch((err) => {
      if(err.name=='PartialFailureError'){
        if (err && err.response.insertErrors != undefined) {
          err.response.insertErrors.forEach((errors) => {
            console.log(errors);
          })
        }
      }else{
            console.log("GENERIC ERROR:",err)
        }
      });
    });

在此之后您最终会注意到错误是由于(再次)incomingData 变量造成的:

Could not parse \'01/01/1970 00:00:00\' as a timestamp. Required format is YYYY-MM-DD HH:MM[:SS[.SSSSSS]]'

您必须将日期从 01/01/1970 00:00:00 更改为 1970-01-01 00:00:00

还在我身边吗?那么在 CF 末尾使用 callback 会产生另一个错误:

这是因为 Cloud Functions 现在需要三个 parameters 而回调是最后一个,因此将函数声明更改为:

exports.subscribe = function (event, context, callback)

完成所有这些之后,您已经能够将数据插入 BigQuery,但是我们使用的是局部变量而不是来自 pub/sub 的数据,此时我放弃了,因为我需要通过使用 Attributes 而不是 data.

实际上重写整个函数以使其工作

所以如前所述,如果您刚开始接触 GCP 世界,请不要遵循本教程。