Firebase firestore 云函数显示错误:无效使用类型“未定义”作为 Firestore 参数

Posted

技术标签:

【中文标题】Firebase firestore 云函数显示错误:无效使用类型“未定义”作为 Firestore 参数【英文标题】:Firebase firestore cloud functions showing Error: Invalid use of type "undefined" as a Firestore argument 【发布时间】:2018-10-11 06:45:25 【问题描述】:

我有一个将货币详细信息添加到 firestore 数据库的项目,我的项目正在使用 ionic 3

每当我向集合中添加新文档时,触发函数 onCreate() 将执行并更新名为“updated”的文档。

但是触发函数总是显示错误。

Error: Invalid use of type "undefined" as a Firestore argument.
    at Object.exports.customObjectError.val [as customObjectError] (/user_code/node_modules/firebase-admin/node_modules/@google-cloud/firestore/src/validate.js:164:14)
    at Function.encodeValue (/user_code/node_modules/firebase-admin/node_modules/@google-cloud/firestore/src/document.js:808:20)
    at Function.encodeFields (/user_code/node_modules/firebase-admin/node_modules/@google-cloud/firestore/src/document.js:678:36)
    at Function.fromObject (/user_code/node_modules/firebase-admin/node_modules/@google-cloud/firestore/src/document.js:218:55)
    at WriteBatch.set (/user_code/node_modules/firebase-admin/node_modules/@google-cloud/firestore/src/write-batch.js:291:39)
    at DocumentReference.set (/user_code/node_modules/firebase-admin/node_modules/@google-cloud/firestore/src/reference.js:419:8)
    at Object.<anonymous> (/user_code/lib/index.js:28:10)
    at next (native)
    at /user_code/lib/index.js:7:71
    at __awaiter (/user_code/lib/index.js:3:12)

请大家帮忙..

我花了很多时间。

代码如下:

import * as functions from 'firebase-functions';

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

exports.createCurrency = functions.firestore
.document('Exchange/ExchangeId')
.onCreate( async (snap, context) => 

const id: string = snap.data().id;
const branchName: string = snap.data().branchName;
const currencyName: string = snap.data().currencyName;
const buyingRate : string = snap.data().buyingRate;
const sellingRate : string = snap.data().sellingRate;


 const newUser= admin.
 firestore()
 .doc(`Exchange/updated`)
 .set(
   id : id,
   branchName : branchName,
   currencyName : currencyName,
   sellingRate : sellingRate,
   buyingRate :buyingRate
  );

 return newUser;


 );

【问题讨论】:

【参考方案1】:

错误信息是这样的:

Invalid use of type "undefined" as a Firestore argument.

您可以在堆栈跟踪中看到,当您使用 DocumentReference 上的对象调用 set() 时会发生这种情况。事实证明,您在对象中传递的值之一是未定义的。检查您传递的每个值,并确保它们都具有实际值:

 .set(
   id : id,
   branchName : branchName,
   currencyName : currencyName,
   sellingRate : sellingRate,
   buyingRate :buyingRate
  );

无法从错误消息中分辨出它是哪一个,因此您必须将它们全部打印出来并检查每一个。

【讨论】:

是的,我知道了。谢谢您的关心 遇到这个问题,令人困惑的是云函数日志输出没有显示undefined 字段 - 正如你所说,“无法从错误消息中判断它是哪一个,所以你必须……检查每一个。” 只有当我在我的代码中发现我正在访问错误的字段对象时,我才意识到我正在为输入设置一个无效的字段数据地图。我没有意识到如果日志输出中没有显示任何无效字段,我应该检查它。在 Web 客户端上,如果您设置了一个 undefined 字段名称,它可以让您在输出中看到它。很高兴知道【参考方案2】:

当您 .set 一个对象但对象中的一个字段未定义时,您将收到此错误。

问题在于,当您使用console.log 显示对象时,它不会显示未定义的变量,因此难以追踪。

使用以下内容而不是 console.log 来查找导致问题的元素。

const util = require('util');
console.log(util.inspect(myObject, showHidden: false, depth: null));

这将为您提供如下输出:

 origin: 'AMS',
  destination: undefined,
  duration: 94,
  carrier: 'KL',
  flight_number: '2977',
  departure: '2019-06-11T15:34:00',
  arrival: '2019-06-11T17:08:00',
  type: 'flight' 

【讨论】:

【参考方案3】:

了解问题:

下面的错误信息比较清楚

无效地将“undefined”类型用作 Firestore 参数。

这意味着,在您的 setupdate 引用方法中,您传递了一个值为 undefined 的参数,根据定义,这不是有效的 Firestore 参数.

解决问题:

我个人觉得举个例子就更容易理解了。

假设我的函数 editStafferPoolPermissions 出现错误,“无效使用类型“未定义”作为 Firestore 参数” 错误消息。其定义如下:

export const editStafferPoolPermissions(data: 
 businessId: string,
 stafferId: string,
 poolPermissions: string[],
 areCustomPermissions: boolean,
 wage: number,
) => //...

找出究竟是哪个参数(甚至参数)

    打开您的 Firebase 开发者控制台并打开“功能”标签。 选择日志标签 过滤掉函数的确切名称并检查传递的参数

这让我们可以看到,哪些参数被传递,哪些没有。

如您所见,我的https云函数的oncall调用中缺少wage参数,导致错误崩溃。 这意味着我要么忘记传递,要么错误传递wage 参数

显然undefined 参数会根据您的函数定义方式保持谨慎,但希望这足以让您了解如何跟踪和解决问题的要点。它通常归结为两个选项,您要么完全忘记传递它,要么从前端错误地传递它(或数据结构不正确)

如果我想允许undefined(可选)参数怎么办?

互联网上的大多数答案都没有解决,我们实际上可能会故意留下一个论点undefined

实际上我很长时间都很难找到这个,当我想创建一个时,我不得不求助于编写一个看起来非常劣质的云函数,里面充满了嵌套的ifs,这也允许可选参数为undefined,如果没有传递则忽略它们。

继续上一个示例,假设我们将 wage 参数更改为可选,即

wage?: number
// ... other params

所以现在,如果我们调用 editStafferPoolPermissions 云函数,工资是否通过都无关紧要。

幸运的是,从 May 29 2020 开始,SetOptions 中添加了一个名为 ignoreUndefinedProperties 的新参数,它允许您简单地忽略 undefined 参数。

例如,我的editStafferPoolPermissions 的内部可能看起来像这样。

await firestore.collection('staffers').doc(stafferId).set(
  poolPermissions,
  areCustomPositions,
  wage,
,  ignoreUndefinedProperties: true )

对旧版 Firebase 版本进行故障排除

鉴于这个新添加的参数是相对较新的,即使在我的工作中,我也使用相对较旧的代码库,由于遗留原因无法拥有最新的 firebase 版本,因此,我需要创建一个 polyfill ,这将模仿 ignoreUndefinedProperties 参数。

我创建了以下函数:

export const ignoreUndefinedSet = async (
  // depending on your namespace
  // & /types version, you can use firebase.firestore.<name> instead
  reference: FirebaseFirestore.DocumentReference,
  data: FirebaseFirestore.DocumentData,
  options?: FirebaseFirestore.SetOptions,
  checkNestedObjects = true,
) => 
  const isPlainObject = (val: unknown) =>
     typeof val === 'object' && val !== null &&
     !(val instanceof Date) && !Array.isArray(val)
  const keepDefinedProperties = (
     obj: FirebaseFirestore.DocumentData,
     nestedCheck = true,
  ) =>
   Object.entries(data).reduce(
      (result, [key, value]) => (
           value === undefined
              ? result
              : (nestedCheck && isPlainObject(value))
                 ? Object.assign(result,  [key]: keepDefinedProperties(value) )
                 : Object.assign(result,  [key]: value )
      ),
      
  )
  const onlyDefinedProperties = keepDefinedProperties(data, checkNestedObjects)
  await reference.set(onlyDefinedProperties,  ...options )

因此,使用我的 polyfill,即使在较旧的 firebase 版本中,您也可以忽略 undefined 属性。 事实上,即使在较新的对象上,它实际上也可能有用,因为它允许您决定是仅在对象根级别忽略 undefined 属性,还是在潜在的嵌套对象属性中忽略。

所以本质上这两个语句是等价的

await reference.set(data,  ignoreUndefinedProperties: true )
// newer firebase version
await ignoreUndefinedSet(reference, data) // my polyfill

注意,你也可以通过其他SetOptions或者禁用嵌套对象检查

await ignoreUndefinedSet(reference, data,  merge: true , false)
// does ignoreUndefinedProperties only at root level and uses the merge method

【讨论】:

以上是关于Firebase firestore 云函数显示错误:无效使用类型“未定义”作为 Firestore 参数的主要内容,如果未能解决你的问题,请参考以下文章

是否可以从firebase云函数node.js更新firestore中的map类型字段?

错误:HTTP 错误 400,请求有错误。 Firebase Firestore 云函数

Firebase 云功能与 Firestore 返回“已超过截止日期”

使用 Python 的 Firebase 云函数?

云函数错误:函数不是有效的特性。必须是数据库、firestore、函数、托管、存储之一[关闭]

将 Firebase 存储下载 URL 推送到 Firebase 云 Firestore