firestore database reference doesnt work with await [duplicate] - javascript

This question already has answers here:
await is only valid in async function
(14 answers)
Closed 11 months ago.
So I'm trying to use the twitter Api to test functionality and do specific tasks. I decided to use firestore to keep the relevant data. However when I create a database reference and try to use await later on in the code, it gives me an error. This is the code.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const {Firestore} = require('#google-cloud/firestore');
const firestore = new firestore();
const dbRef = firestore.doc('tokens/demo');
const TwitterApi = require('twitter-api-v2').default;
const twitterClient = new TwitterApi({
clientId: 'clientid',
clientSecret: 'clientsecret',
});
const callbackURL = 'http://127.0.0.1:5001/twbt-ad868/us-central1/callback';
// STEP 1 - Auth URL
exports.auth = functions.https.onRequest((request, response) => {
const { url, codeVerifier, state } = twitterClient.generateOAuth2AuthLink(
callbackURL,
{ scope: ['tweet.read', 'tweet.write', 'users.read', 'offline.access'] }
);
// store verifier
await dbRef.set({ codeVerifier, state });
response.redirect(url);
});
exports.callback = functions.https.onRequest((request, response) => {
});
exports.tweet = functions.https.onRequest((request, respone) => {});
and this is the error I get
await dbRef.set({ codeVerifier, state });
^^^^^
SyntaxError: await is only valid in async function
I've tried using this code instead to reference the json file in firestore, but I still get the same error
const dbRef = admin.firestore().doc('tokens/demo');
I'm assuming this is because my program isn't properly accessing the database in firestore? When I run this command
gcloud firestore operations list
I get
Listed 0 items.
If this is the case I'm not sure how to fix this and have my code access the database properly
Thank you in advance for any help you can provide me.

You must create an async function in order to have an await since it requires a promise.
async function () { await dbRef.set({ codeVerifier, state });}

Related

Firebase cloud functions - Can't create an array from the data after fetching from 3rd party API inside the function

I've been trying to implement firebase cloud functions on my project, currently cloud functions are working fine but whenever I try to fetch something from the third-party API the data is fetched but the data isn't being pushed to the array firestoreValues.
I don't think this is a problem related to firebase cloud function, rather some mistake on my end with javascript.
const functions = require("firebase-functions");
const fetch = require("node-fetch");
const admin = require("firebase-admin");
admin.initializeApp();
exports.executeTask = functions.firestore
.document("tasks/{taskId}")
.onCreate(async (doc, ctx) => {
const { service, uid, request } = doc.data();
//firestoreValues initialised wrong?
var firestoreValues = [];
if (service == "Email Validator") {
const emails = request;
emails.forEach((element) => {
const options = {
method: "GET",
headers: {
"X-RapidAPI-Key":
"RAPID-API-KEY",
"X-RapidAPI-Host": "RAPID-API-host",
},
};
const fetchFromURL = async () =>
await (
await fetch(
`https://domain/?domain=${element}`,
options
)
).json();
fetchFromURL().then((data) => {
console.log("data", data);
console.log("firestoreValuesinside", firestoreValues);
firestoreValues.push(data);
});
});
}
return admin
.firestore()
.collection("taskResults")
.doc(doc.id)
.set({ uid: uid, taskId: doc.id, result: firestoreValues });
});
the firestoreValues variable isnt changing and on the task results result an empty array is being written. How can I store the response data after every response to the firestoreValues
Ive tried to change the var to const and let for firestoreValues but the data isnt being pushed and the final result:firestoreValues on the .set() remains empty.

Async/Await don't work in Google cloud functions

I work with google cloud functions and cloud messaging on Firebase. However, when I try to use Async/Await functions, I have an error: error Parsing error: Unexpected token =>
I work with Node.js v16.
Here is my code:
const functions = require("firebase-functions");
// const mess = require("firebase/messaging");
const admin = require("firebase-admin");
exports.sendListenerPushNotificationProductUpdate = functions.database
.ref("Products/{product}/type/")
.onUpdate(async (snapshot, context) => {
...
const tokensSnapshot = await Promise.resolve(getDeviceTokensPromise);
console.log("TOKEN: " + JSON.stringify(tokensSnapshot));
// Check if there are any device tokens.
if (!tokensSnapshot.hasChildren()) {
return functions.logger.log(
"There are no notification tokens to send to."
);
}
...
// Listing all tokens as an array.
const tokens = Object.keys(tokensSnapshot.val());
// Send notifications to all tokens.
const response = await admin.messaging().sendToDevice(tokens, payload);
// For each message check if there was an error.
const tokensToRemove = [];
return Promise.all(tokensToRemove);
});
Does getDeviceTokensPromise return a Promise? If so, that line should just be
const tokensSnapshot = await getDeviceTokensPromise()

Setting collection name in Firebase function

Just starting to use Firebase functions and have the sample working, but confused because the update event doesn't occur if I change the 'messages' collection to a different name, eg 'listings'. I change the word 'messages' in two places, on the 'add' and the 'makeUppercase' line. I get the response OK, it writes the data to the collection, but doesn't fire the event. Must be simple, but can't google it.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.addMessage = functions.https.onRequest(async (req, res) => {
// Grab the location parameter.
const inputcode = req.query.code || 'blank';
// Push the new message into Cloud Firestore using the Firebase Admin SDK.
const writeResult = await admin.firestore().collection('messages').add({inputcode: inputcode});
// Send back a message that we've succesfully written the message
res.json({result: `Message with ID: ${writeResult.id} added.`});
});
exports.makeUppercase = functions.firestore.document('/messages/{documentId}')
.onCreate((snap, context) => {
// Grab the current value of what was written to Cloud Firestore.
const inputcode = snap.data().inputcode;
// Access the parameter `{documentId}` with `context.params`
functions.logger.log('Uppercasing', context.params.documentId, inputcode);
const areacode = inputcode.toUpperCase();
const written = new Date();
return snap.ref.set({written, areacode}, {merge: true});
});
I'm using the local firebase emulator to do this test, by the way.
This is the new version, ony changing 'messages' to 'vvvv' in two places.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.addMessage = functions.https.onRequest(async (req, res) => {
// Grab the location parameter.
const inputcode = req.query.code || 'blank';
// Push the new message into Cloud Firestore using the Firebase Admin SDK.
const writeResult = await admin.firestore().collection('vvvvv').add({inputcode: inputcode});
// Send back a message that we've succesfully written the message
res.json({result: `Message with ID: ${writeResult.id} added.`});
});
exports.makeUppercase = functions.firestore.document('/vvvvv/{documentId}')
.onCreate((snap, context) => {
// Grab the current value of what was written to Cloud Firestore.
const inputcode = snap.data().inputcode;
// Access the parameter `{documentId}` with `context.params`
functions.logger.log('Uppercasing', context.params.documentId, inputcode);
const areacode = inputcode.toUpperCase();
const written = new Date();
return snap.ref.set({written, areacode}, {merge: true});
});
OK. Doug, your suggestion sank in after an hour or so! I've restarted everything and think that I understand. If I change the name in those two places, without restarting, the collection.add function takes place and I can see the record in the new collection, but the onCreate event didn't fire. I had to restart the whole service to restart buth parts. I was getting confused because one part was working and not the other. Thanks for your patience.

How to fix firebase database initialised multiple times due to React SSR initialised database and cloud function firebase initialised database?

I have updated the question as found the root cause of the issue.
As I have hosted my React SSR app which uses firebase database in the client serving by one of the cloud function named app throwing an error of Error: FIREBASE FATAL ERROR: Database initialized multiple times. Please make sure the format of the database URL matches with each database() call.. When I comment out one by one and deploy, works perfectly. But when I deploy together doesn't work. How do I separate these two keeping both at the same repo?
ORIGINAL Question: Why firebase cloud function throwing an error of 'The default Firebase app does not exist.'?
So I am trying out firebase function for the first time. admin.messaging() throwing me the following error. Help me figure out why?
If I look at the console I get results till console.log('deviceToken', deviceToken);
so whats wrong in const messageDone = await admin.messaging().sendToDevice(deviceToken, payload);?
const functions = require('firebase-functions');
const admin = require('firebase-admin');
exports.updateUnreadCount = functions.database.ref('/chats/{chatId}/{messageId}')
.onCreate(async(snap, context) => {
const appOptions = JSON.parse(process.env.FIREBASE_CONFIG);
appOptions.databaseAuthVariableOverride = context.auth;
const adminApp = admin.initializeApp(appOptions, 'app');
const { message, senderId, receiverUid } = snap.val();
console.log(message, senderId, receiverUid);
console.log('------------------------');
const deleteApp = () => adminApp.delete().catch(() => null);
try {
const db = adminApp.database();
const reciverUserRef = await db.ref(`users/${receiverUid}/contacts/${senderId}/`);
console.log('reciverUserRef', reciverUserRef);
const deviceTokenSnapshot = await reciverUserRef.child('deviceToken').once('value');
const deviceToken = await deviceTokenSnapshot.val();
console.log('deviceToken', deviceToken);
const payload = {
notification: {
title: 'Test Notification Title',
body: message,
sound: 'default',
badge: '1'
}
};
const messageDone = await admin.messaging().sendToDevice(deviceToken, payload);
console.log('Successfully sent message: ', JSON.stringify(messageDone));
return deleteApp().then(() => res);
} catch (err) {
console.log('error', err);
return deleteApp().then(() => Promise.reject(err));
}
});
Update1: According to this https://firebase.google.com/docs/cloud-messaging/send-message#send_to_a_topic, admin.messaging().sendToDevice(deviceToken, payload) APIs are only available in the Admin Node.js SDK?
So switched to
const payload = {
data: {
title: 'Test Notification Title',
body: message,
sound: 'default',
badge: '1'
},
token: deviceToken
};
const messageDone = await admin.messaging().send(payload);
Which is not working either. Getting an error Error: The default Firebase app does not exist. Make sure you call initializeApp() before using any of the Firebase services. Any lead will be helpful.
EDIT: Finally got the function working.
My index.js is exporting to functions, follwoing
exports.app = functions.https.onRequest(app); //React SSR
exports.updateChat = functions.database.ref('/chats/{chatId}/{messageId}').onCreate(updateChat);
exports.app is a react ssr function, which I am using to host my site. This uses database too. and throwing error of multiple database instance.
When I comment out one by one and deploy, works perfectly. But when I deploy together doesn't work. How do I separate these two keeping both at the same repo? Any suggestions, please?
You can initialise db outside export function.
const admin = require('firebase-admin');
const adminApp = admin.initializeApp(appOptions, 'app')
//continue code
Update:
const admin = require('firebase-admin');
const adminApp = admin.initializeApp(options);
async function initialize(options, apps = 'app') {
try {
const defaultApp = adminApp.name
if(defaultApp) {
const adminApp1 = admin.initializeApp(apps);
}else {
const adminApp1 = admin.initializeApp(options, apps);
}
}catch(err) {
console.error(err);
}
}
Modify this snippet as per your need and try it out
It abstracts initialize of app in another function. Just call this function at appropriate place in your code.

The functions of the firebase tutorial do not work

I tried to implement firebase functions from the tutorial: https://firebase.google.com/docs/functions/get-started
This is my code bellow. When I try to call the url https://us-central1-skoon-5ed4d.cloudfunctions.net/addMessage I hava an "Error: could not handle the request"
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.addMessage = functions.https.onRequest(async (req, res) => {
const original = req.query.text;
const snapshot = await admin.database().ref('/messages').push({original: original});
Firebase console.res.redirect(303, snapshot.ref.toString());
});
exports.makeUppercase = functions.database.ref('/messages/{pushId}/original')
.onCreate((snapshot, context) => {
// Grab the current value of what was written to the Realtime Database.
const original = snapshot.val();
console.log('Uppercasing', context.params.pushId, original);
const uppercase = original.toUpperCase();
// You must return a Promise when performing asynchronous tasks inside a Functions such as
// writing to the Firebase Realtime Database.
// Setting an "uppercase" sibling in the Realtime Database returns a Promise.
return snapshot.ref.parent.child('uppercase').set(uppercase);
});
I removed async and await and in my log I have Error:
Reference.push failed: first argument contains undefined in property 'messages.original'
at validateFirebaseData (/srv/node_modules/#firebase/database/dist/index.node.cjs.js:1433:15)
at /srv/node_modules/#firebase/database/dist/index.node.cjs.js:1479:13
at Object.forEach (/srv/node_modules/#firebase/util/dist/index.node.cjs.js:837:13)
at validateFirebaseData (/srv/node_modules/#firebase/database/dist/index.node.cjs.js:1462:14)
at validateFirebaseDataArg (/srv/node_modules/#firebase/database/dist/index.node.cjs.js:1421:5)
at Reference.push (/srv/node_modules/#firebase/database/dist/index.node.cjs.js:14087:9)
at exports.addMessage.functions.https.onRequest (/srv/index.js:23:54)
at cloudFunction (/srv/node_modules/firebase-functions/lib/providers/https.js:57:9)
at /worker/worker.js:724:7
at /worker/worker.js:707:11

Categories

Resources