when i use firebase.database().goOnline(); I get an error - node.js

this is my code
admin.initializeApp({...});
var db = admin.database();
let ref = db.ref(...);
await ref.once("value",function () {...},);
firebase.database().goOffline();
firebase.database().goOnline();
ref.on("value",function () {...},);
);
when i use firebase.database().goOnline(); I get an error
Firebase: No Firebase App '[DEFAULT]' has been created - call Firebase App.initializeApp() (app/no-app).
at app

You're mixing two ways of addressing Firebase.
You can access Firebase through:
Its client-side JavaScript SDK, in which case the entry point is usually called firebase.
Its server-side Node.js SDK, in which case the entry point is usually called admin.
Now you initialize admin, but then try to access firebase.database(). And since you did call admin.initializeApp that's where the error comes from.
My guess is that you're looking for admin.database().goOnline() or db.goOnline().
Also note that there is no reason to toggle goOffline()/goOnline() in the way you do now, and you're typically better off letting Firebase manage that on its own.

Related

How to create a Flutter Stream using MongoDB (watch collection?) with Firebase Cloud Function

I've been trying out MongoDB as database for my Flutter project lately, since I want to migrate from pure Firebase database (some limitations in Firebase are an issue for my project, like the "in-array" limit of 10 for queries).
I already made some CRUD operations methods in some Firebase Cloud Functions, using MongoDB. I'm now able to save data and display it as a Future in a Flutter App (a simple ListView of Users in a FutureBuilder).
My question is : how would it be possible to create a StreamBuilder thanks to MongoDB and Firebase Cloud Functions ? I saw some stuff about watch collection and Stream change but nothing clear enough for me (usually I read a lot of examples or tutorial to understand).
Maybe some of you would have some clues or maybe tutorial that I can read/watch to learn a little bit more about that subject ?
For now, I have this as an example (NodeJS Cloud Function stored in Firebase), which obviously produces a Future in my Future app (not realtime) :
exports.getUsers = functions.https.onCall(async (data, context) => {
const uri = "mongodb+srv://....";
const client = new MongoClient(uri);
await client.connect();
var results = await client.db("myDB").collection("user").find({}).toArray();
await client.close();
return results;
});
What would you advice me to obtain a Stream instead of a Future, using maybe watch collection and Stream change from MongoDB, providing example if possible !
Thank you very much !
Cloud Functions are meant for short-lived operations, not for long-term listeners. It is not possible to create long-lived connections from Cloud Functions, neither to other services (such as you're trying to do to MongoDB here) nor from Cloud Functions back to the calling client.
Also see:
If I implement onSnapshot real-time listener to Firestore in Cloud Function will it cost more?
Can a Firestore query listener "listen" to a cloud function?
the documentation on EventArc, which is the platform that allows you build custom triggers. It'll be (a lot* more. involved though.

Deploying firebase cloud function fails when I initialise firebase with a service account key

so very recently I started using google's firebase cloud functions, and loved it immediately! I very quickly restructured a project I was going to work on, and included firebase in it, so I could use the cool features of firestore, in combination with cloud functions.
Up until today, everything went on smoothly; pretty much, until I decided to play with google's FCM (Firebase Cloud Messaging) to send notifications via node js. Before this, I had created some really dense functions and already deployed to my console which were working seamlessly.
The tricky part is, at the time I created and deployed these functions, I initialised my firebase app in node js with admin.initalizeApp().
With this, everything worked fine(both locally & deployed) until I tried to use admin.messaging().sendToDevice... which resulted in a very nasty error, that basically told me I couldnt send notifications if I wasnt authenticated..
The error
(Error: An error occurred when trying to authenticate to the FCM servers. Make sure the credential used to authenticate this SDK has the proper permissions. See https://firebase.google.com/docs/admin/setup for setup instructions. Raw server response: "<HTML>
> <HEAD>
> <TITLE>Unauthorized</TITLE>
> </HEAD>
> <BODY BGCOLOR="#FFFFFF" TEXT="#000000">
> <H1>Unauthorized</H1>
> <H2>Error 401</H2>
> </BODY>
> </HTML>
> ". Status code: 401.)
Following the error, I used a few tips from some other users on stack overflow who had faced this error, and most of them suggested that I download a service key from my console, and initialise my firebase app with admin.initializeApp({credential:admin.credential.cert(serviceAccount)})
This solution worked beautifully, as it allowed me to test my notification without seeing the above error ever again.
However, when all my tests were done, and I was ready to deploy, the new function I had just created to work on notification, as well as all my previously deployed functions could not get deployed. All of a sudden, the old working functions in my console had a red exclamation mark beside them, and I had to get rid of them. Even after I cleared out all of my console and tried to redeploy all my functions, it failed, and failed and failed with no errors(context: I wasted the whole day!!! lool!) Every tip on the internet failed for me, until I reverted back to my old way of initialising my firebase app admin.initializeApp(), then booom! all my functions uploaded successfully, and then again, the authentication error appeared again when I tried to retest my notification function.....
I guess my question is: is there anything I don't know about deploying functions to the firebase console with my app initialised with a service account key I downloaded from my console?
Is there something else I need to do to get my functions to deploy properly every time I init my firebase admin app with a service account key?? Because initialising the app with just .initalizeApp() works fine for all other purposes both locally and when deployed, except when using FCM. Can anyone please help with what is happening here??
I think it can be solved by initializing two apps and using them as objects described here. One with credentials that work for other functions and one for messaging.
If you need it only for one function you can do it even inside it. I have tested it like this:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp({
credential: admin.credential.applicationDefault()
});
exports.first_app = functions.https.onRequest(async (req, res) => {
res.json(admin.app().name);
})
exports.other_app = functions.https.onRequest(async (req, res) => {
var otherApp = admin.initializeApp({
credential: **<< different credential here >>**
}, "2nd_app");
res.json(otherApp.name);
})
as already mentioned, you should initialize a second app just for the new function you are creating. You should put the initialization code inside the new function like this
export const saveMap = functions.https.onRequest(async (req, response) => {
const serviceAccount = require("./../serviceAccountKey.json");
admin.initializeApp({
projectId: "serviceAccount.project_id",
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://your_project_id_here.firebaseio.com", //update this
storageBucket: "your_bucket_name_here.appspot.com" //update this
}, "2nd_app")
I had the same issue and once I put the second initialization code into the new function, it worked. Note that in this code the serviceAccountKey.json is in the same folder as src and lib.

Is it possible to have a Firebase Function that is triggered by changes to a Firestore that lives in a seperate Firebase project to the Function?

Let's say I have a Firebase project named "A". Within this project, I have a Cloud Firestore triggered Firebase function that needs to run when a document within Firestore changes. By default, the Firebase Function will listen to changes within Firestore on project A.
However, let's say I have a particular use case where there is a second Firebase project named "B". I need the Firebase Function within Project A to be triggered on Firestore changes that happen to Firestore within project B.
Is this possible? Firebase docs do show initializing multiple projects, which would allow me to connect to multiple databases as such:
const admin = require("firebase-admin");
const serviceAccount = require("path/to/serviceAccountKey.json");
const secondaryAppConfig = {
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://<DATABASE_NAME>.firebaseio.com"
};
// Initialize another app with a different config
const secondary = firebase.initializeApp(secondaryAppConfig, "secondary");
// Retrieve the database.
const secondaryDatabase = secondary.database();
But this doesn't allow me to trigger a Firestore Triggered Firebase Function on my secondary project. Firebase functions call the firebase-functions methods directly, whereas calling a database calls the initialized project.
const functions = require('firebase-functions');
exports.myFunction = functions.firestore
.document('...')
.onWrite((change, context) => { /* ... */ });
Is what I would like to do possible? Or does anyone have a workaround (other than creating this Firebase Function within project B)?
It's not possible. Cloud Functions triggers can only fire in response to changes in the resources of the project where they are deployed. This is true for all types of triggers, including Firestore.
If you want code to run in response to changes in another project, the function will have to be deploy to that project.
Currently it is only possible for writes to Cloud Firestore to trigger Cloud Functions that are part of the same project. It is not possible to trigger Cloud Functions that are defined in another project.
The typical solution is for example to call a HTTP Function in the secondary project, for which you can then configure the complete URL.
I'm not sure it can be done all in one codebase - that's from a lack of experience though. I'd say, given your setup, your calling function can trigger your callee function via HTTP call (documentation)
This might require a paid Firebase plan, but I'm not certain of it (source)

How do i reference Firebase's realtime database from within a cloud function?

In a Firebase Cloud function i am attempting to retrieve data from my Realtime Database and write an update to it as well. This is where i am having trouble.
The function:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
...
api.post('/messages/add', (request: any, response: any) => {
const dbRef:any = functions.database.ref(`count/${request.body.chatRoomId}`);
dbRef.once('value').then((snapshot:any) => {
let messageCount:number = (snapshot.val() && snapshot.val().messages) || 0;
messageCount = Number(messageCount + 1);
dbRef.update({
messages: messageCount,
updated: admin.database().database.ServerValue.TIMESTAMP
});
});
});
When i call this function from the client, in the firebase cloud console logs, i am seeing the following error:
TypeError: dbRef.once is not a function
I have tried referencing the database in each of the following ways, all of which fail:
functions.database.ref(`count/${request.body.chatRoomId}`).once('value').then((snapshot)) =>
functions.database.ref(`count/${request.body.chatRoomId}`).once('value', (snapshot) =>
admin.database().ref(`count/${request.body.chatRoomId}`).once('value').then((snapshot)) =>
admin.database().ref(`count/${request.body.chatRoomId}`).once('value', (snapshot) =>
When attempting the reference using the Admin SDK via admin.database() i get a different error:
TypeError: Cannot read property 'ServerValue' of undefined
at dbRef.once.then
Lastly, i can confirm that the value for ${request.body.chatRoomId} is resolving correctly, i had tested this by printing its value to the console.
The answer here shows how to reference the realtime database from the 'event' response within a realtime database listener like onWrite() for example, however my function is not triggered by realtime database changes, but rather is an endpoint reachable from the client.
UPDATE
The answer proposed by Doug Stevenson below is correct but there was also an additional error due to attempting to write a timestamp incorrectly to a field that i had initially excluded which was causing my function to fail despite having tried his solution, thus I have updated the code to reflect this.
First, the answer is to reference the Realtime Database with admin.database()
Second, even though i had tried this, i was still seeing an error, but the error was due to attempting to set a timestamp incorrectly. Thanks to Frank van Puffelen for pointing this out.
This: admin.database().database.ServerValue.TIMESTAMP
Needs to be: admin.database.ServerValue.TIMESTAMP
And with that it works.
You're making the mistake of trying to use the functions SDK to query the database. This is not actually creating a database reference:
functions.database.ref(`count/${request.body.chatRoomId}`);
The functions SDK is just used for declaring and configuring Cloud Functions.
What you should be doing instead is using the Admin SDK to create a reference, then query it:
admin.database().ref(...).once(...)
You also need to initialize the Admin SDK exactly once before you use it:
admin.initializeApp();

How to use Firebase Database in Google Actions?

I'm new to programming Actions for Google Home/Assistant.
I have been using the Inline-Editor under Fulfilment lately and it works fine. Now I want to start using the Firebase DB.
As it says const functions = require('firebase-functions'); in the first lines of the Inline Editor I am assuming, that the Database is ready to use?
If so, how do I access it?
Although Dialogflow uses Firebase Functions to let you do inline code-editing, it doesn't sound like it is a full-fledged Firebase environment. There may be APIs on the back-end that are not setup.
The Dialogflow In-line Fulfillment is meant for simple logic testing and simple operations.
Fortunately - it isn't difficult to take that code and expand it into code that you write... and still host on Firebase Functions! See https://firebase.google.com/docs/functions/get-started for the tools you'll need to install to get started.
For a more extensive tutorial about writing Firebase Functions that work with Dialogflow and getting started with Firebase Functions, you can take a look at the codelab from Google at https://codelabs.developers.google.com/codelabs/assistant-dialogflow-nodejs/index.html
You can use the Google Realtime Database package firebase-admin
const admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
const db = admin.database();
const ref = db.ref("/");
And to set a value in the database
ref.set({yourKey: 'value'});

Resources