【问题标题】:Firebase firestore cloud functions showing Error: Invalid use of type "undefined" as a Firestore argumentFirebase firestore 云函数显示错误:无效使用类型“未定义”作为 Firestore 参数
【发布时间】: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;


 });

【问题讨论】:

    标签: javascript firebase google-cloud-firestore google-cloud-functions


    【解决方案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,
      }) => //...
      

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

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

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

      如您所见,我的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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-26
        • 2018-06-01
        • 1970-01-01
        • 2021-06-23
        • 1970-01-01
        • 1970-01-01
        • 2019-02-26
        • 2019-08-28
        相关资源
        最近更新 更多