Firebase firestore cloud functions showing Error: Invalid use of type “undefined” as a Firestore argument

后端 未结 3 436
独厮守ぢ
独厮守ぢ 2021-01-07 17:05

I have a project to add currency details into the firestore database and my project is doing with ionic 3

Whenever I add a new document to the collection a trigger f

相关标签:
3条回答
  • 2021-01-07 17:37

    The error message is this:

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

    You can see in your stack trace that this happens when you call set() with an object on a DocumentReference. It turns out that one of the values you're passing in the object is undefined. Check each of the values that you're passing and make sure all of them have an actual value:

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

    It's impossible to tell which one it is from the error message, so you'll have to print them all out do something to check each and every one of them.

    0 讨论(0)
  • 2021-01-07 17:41

    Understanding the issue:

    The following error message is relatively clear

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

    This means, that in your set or update reference method, you've passed an argument, which had value of undefined, which is by definition not a valid Firestore argument.

    Fixing the issue:

    Personally I find everything much easier to understand with an example.

    Let's say my function editStafferPoolPermissions errors with the "Invalid use of type "undefined" as a Firestore argument" error message. Which is defined the following way:

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

    To find out which argument (or even arguments) it is exactly

    1. Open your Firebase developer console and open the "Functions" tab.
    2. Select the logs tab
    3. Filter out the exact name of the function and check the arguments passed

    This allow us to see, which arguments were passed and which weren't.

    As you can see, the wage parameter is missing in the oncall invocation of my https cloud function, causing the error to crash. This means I either forgot to pass or am passing the wage parameter incorrectly.

    Obviously the undefined argument will wary depending on how your function is defined but hopefully this should be enough for you to get the gist of how to trace and fix the issue. It usually boils down to two options, you either forgot to pass it altogether or are passing it incorrectly from the front-end (or the data is incorrectly structured)

    What if I want to allow undefined (optional) arguments?

    What most of the answers on internet don't tackle, is the scenario where we might actually leave an argument undefined on purpose.

    I actually had a lot of trouble finding this for the longest time, where I had to resort to writing a very shoddy looking cloud funciton full of nested ifs, when I wanted to create one, that would also allow optional parameters as undefined and simply ignore them if they aren't passed.

    To continue from our previous example, let's say we changed the wage argument to optional, i.e.

    wage?: number
    // ... other params
    

    So now, if we call the editStafferPoolPermissions cloud functions, it shouldn't matter whether the wage is passed or not.

    Luckily, as of May 29 2020, there has been added a new argument to the SetOptions called ignoreUndefinedProperties, which allows you to simply ignore undefined parameters.

    For example, the inside of my editStafferPoolPermissions could look something like this.

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

    Troubleshooting legacy firebase versions

    Given this newly added argument is relatively recent and even in my work I was on relatively older codebase which for legacy reasons could not have the most up-to-date firebase version, so for this reason, I needed to create a polyfill, which would mimic the ignoreUndefinedProperties argument.

    I've created the following function:

    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 })
    }
    

    So with my polyfill, you can use ignore the undefined properties even in older firebase versions. In fact it actually might be useful even on newer ones, because it allows you to decide if you want to ignore the undefined properties only at the object root level, or also at potentially nested object properties.

    So essentially these two statements are equivalent

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

    Note, you can also pass other SetOptions or disable the nested objects check

    await ignoreUndefinedSet(reference, data, { merge: true }, false)
    // does ignoreUndefinedProperties only at root level and uses the merge method
    
    0 讨论(0)
  • 2021-01-07 17:55

    When you .set an object but one of the fields in the object is undefined you will get this error.

    The problem is that when you use console.log to display the object it does not show the undefined variables so it is difficult to trace.

    Use the following instead of console.log to find the element that is causing the problem.

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

    This will give you an output as follows:

    { 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' }
    
    0 讨论(0)
提交回复
热议问题