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
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.
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.
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
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)
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 if
s, 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 })
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
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' }