Reputation: 34523
This question is similar but didn't help.
The goal is to use async/await with Firebase Cloud Firestore queries instead of the then/catch Promise code from the Firebase documentation.
However, the function below rejects successfully in the negative case, but returns Promise { <pending> }
instead of the Cloud Firestore doc.
async getUser(emailAddress) {
// Return null if @emailAddress blank.
if (!emailAddress) {
return null;
}
// Assume @db points to a Cloud Firestore database. Query only returns one doc.
let query = db.collection('users').where('emailAddress', '==', emailAddress);
try {
let querySnapshot = await query.get();
querySnapshot.forEach(function(doc) {
return doc.data();
});
} catch(e) {
console.log('Error getting user: ', e);
}
}
Upvotes: 2
Views: 2447
Reputation: 83191
If emailAddress
is not null or undefined, your function returns nothing becauseforEach()
returns void.
Since you have only one doc in the querySnapshot
you can do as follows:
async getUser(emailAddress) {
// Return null if @emailAddress blank.
if (!emailAddress) {
return null;
}
// Assume @db points to a Cloud Firestore database. Query only returns one doc.
const query = db.collection('users').where('emailAddress', '==', emailAddress);
try {
const querySnapshot = await query.get();
return querySnapshot.docs[0].data();
} catch(e) {
console.log('Error getting user: ', e);
}
}
Note that your getUser()
function is itself asynchronous, so you need to use then()
(or async/await) to get the doc value when the Promise it returns is fulfilled.
const emailAddress = "[email protected]";
getUser(emailAddress).
then(userData => { ... })
Upvotes: 3
Reputation: 2268
You are trying to return from forEach
, but forEach
doesn't return anything, rather it loops through elements and allows you to modify them.
You can modify your code like this for example:
async getUser(emailAddress) {
// Return null if @emailAddress blank.
if (!emailAddress) {
return null;
}
// Assume @db points to a Cloud Firestore database. Query only returns one doc.
let query = db.collection('users').where('emailAddress', '==', emailAddress);
try {
const results = [];
let querySnapshot = await query.get();
querySnapshot.forEach(function(doc) {
results.push(doc.data());
});
return results;
} catch(e) {
console.log('Error getting user: ', e);
}
}
More info about forEach:
forEach() executes the callback function once for each array element; unlike map() or reduce() it always returns the value undefined and is not chainable. The typical use case is to execute side effects at the end of a chain.
Upvotes: 3
Reputation: 317928
async
functions, such as yours, always return a promise. That can't be avoided. All of the asynchronous behavior is still there in the function, and the caller still has to await
or then
to get the value in the promise. You can't use async/await to remove a promise and return immediately.
On top of that, your function doesn't actually return any documents. The return inside the forEach
is actually just returning from the inline lambda function that you passed to forEach
. That return doesn't extend to the enclosing getUser
function.
If you want to use async/await effectively, the function still has to return a value from its top level. And the caller still has to use await or then to get the value out of the returned promise.
Upvotes: 2