Firebase invoke realtime database onCreate function locally - node.js

I have made a testing environment and try to invoke Firebase Realtime Database onCreate function locally with test data through Cloud Functions shell looking at the documents. But it gives an error. I may have misunderstood something.
functions: TypeError: instance.INTERNAL.registerComponent is not a function at registerDatabase...
The code I try:
const testData = require('./test/testData.json')
requestSubmission(testData, {params:{accountKey: '-LwOLg3hWxXd8iNWBrUt', requestKey: '-M0Z5m8gGtfrgAER5KF'}})
My cloud function:
exports.requestSubmission = functions.database.ref('/requests/{accountKey}/{requestKey}')
.onCreate((snap, context) => {
//This is my original function.
});

I found the solution for my problem while checking issues on github. I installed it in functions folder.
npm install #firebase/app --save

Related

how to make my Google Cloud functions not deployed when performing testing?

say for example in my index.ts I have this code below
exports.makeUppercase = functions.firestore.document('/messages/{documentId}')
.onCreate((snap, context) => {
});
exports.clearOtherDocs = functions.firestore.document('/messages/{documentId}')
.onDelete((snap, context) => {
});
// actually I have more than 15 functions like that located in some files (not only in index.ts )
currently I am testing my cloud functions using Mocha / Jest. and if those functions is deployed (locally using emulator), then those Firestore triggers will ruin my tests.
so how to make those Firestore triggers will not be deployed locally when I am performing testing using Mocha?
I think I find the solution.
before running the testing, instead of run all emulators using
firebase emulators:start
I need to just run the emulator needed. in my case, I only need firestore and authentication emulators, so I run this code below before run the script testing
firebase emulators:start --only firestore,auth

Firestore onUpdate function not triggering

The problem
I'm using Firebase cloud functions with the emulator, and for some reason, the onUpdate trigger is not triggering, yet the onCreate function does trigger.
All code is TypeScript, and it's transpiled to JS to work on cloud functions.
// functions/src/music.ts
// this function runs
export const onMusicCreated = functions.firestore
.document('music/{musicId}')
.onCreate(async (snapshot) => {
console.log('on create is running')
})
// this function doesn't run
export const onMusicUpdated = functions.firestore
.document('music/{musicId}')
.onUpdate(async (change) => {
console.log('on update is running')
})
Both functions are async because in the final code,
On the front-end, when I run the add function on the front-end, the onCreate function fires.
const { id } = await firebase.firestore().collection('music').add({ title: 'hello world' })
The console log runs as expected and the emulator outputs this into the console:
i functions: Beginning execution of "onMusicCreated"
i functions: Finished "onMusicCreated" in ~1s
Yet when I update that same document, the onUpdate function doesn't run.
// "id" is the same id as above
await firebase.firestore().doc(`music/${id}`).update({ title: 'new title' })
Nothing happens. I can confirm that the document is actually updated when I look in the firestore emulator. Am I missing something obvious? The front-end code is simplified as compared to my actual use, but the functions code isn't simplified at all. And I can confirm that the firestore document is created and updated as I'd expect.
No error messages in the console or the logs.
Debug steps
I've checked to make sure the functions code was correctly transpiled to JS. I bothed looked at the code output, as well as updated the onCreate code multiple times to ensure that function updated
I hollowed out all my code inside the functions (as shown above), so I can confirm that the function itself isn't running
The onUpdate function technically accepts two parameters. Same results with both parameters.
I have not tried the functions in production, only with the emulator.
Related posts
Why doesn't firestore onWrite trigger get invoked on firebase cloud functions emulator?
I'm not using any forbidden characters in the document selector, or at least I'm not getting that error message.
Firebase Cloud Functions for Firestore are not triggering
Using functions 3.11.0, and the functions are async, hence they should implicitly return Promise. Results are the same when explicetely returning a value (e.g., return 0)
https://firebase.google.com/docs/functions/firestore-events#trigger_a_function_when_a_document_is_updated
That's the official docs. As far as I can tell, I'm doing what the docs say. I could just be missing something blindingly obvious, though.
Other details
macOS Big Sur 11.1 (20C69)
Firebase CLI 9.1.0
The emulator should be up-to-date
Any ideas? Thanks!
Turns out I just forgot to import onMusicUpdated in the index.ts functions file. Hence the emulator never knew it existed!
Changed
// functions/src/index.ts
export { onMusicCreated } from './music'
to
// functions/src/index.ts
export { onMusicCreated, onMusicUpdated } from './music'

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();

What is the difference between Firebase SDK and Firebase SDK for cloud functions?

I don't understand the difference between Firebase SDK and Firebase SDK for cloud functions. I mean, when you run in command line "firebase init" in node.js, node modules will be downloaded to initialize a new project. But if i run "npm install firebase" different node modules appears, with similar names and different contents. So the question is: which SDK should I use to run functions and authentication in the same code? (I got a lot of require error from importing similar things and I don't know how to solve the problem).
Here is the code:
const functions = require('firebase-functions');
var firebase = require('firebase');
firebase.initializeApp();
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});
exports.delete = functions.https.onRequest((request, response) => {
console.log("delete");
});
The error says firebase.auth() is not a function, maybe for bad import and I don't know which package I need to import
npm install firebase installs modules to be used in client code that accesses Firebase products such as Firebase Authentication, Realtime Database, Firestore, and Cloud Storage.
npm install firebase-functions install modules to be used when writing backend code to deploy to Cloud Functions.
You're trying to use the Firebase Authentication client side library to listen to auth state changes in Cloud Functions. This isn't going to work, since that auth library only works on web clients.

Firebase Node.js admin SDK timeouts when trying to access Realtime DB

Using the Node.js admin SDK with Firebase Functions I get a timeout whenever I try to access the Realtime Database. This occurs only when testing a function locally (firebase serve --only functions,hosting) and when the default app is initialized using the functions.config().firebase.
This is a new behavior that started just a couple a days ago. However, if I try to initialize the default app with the serviceAccount.json file everything works as expected.
I'm using firebase-admin version 4.2.1 and firebase-functions version 0.5.9.
I wrote a straight forward http triggered function that fails due to timeout:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const db = admin.database();
exports.testDbConnection = functions.https.onRequest((req, res) => {
return admin.database().ref().once('value')
.then(function(snapshot) {
res.json(snapshot);
}).catch(function(error) {
res.json(error);
});
});
from the documentation
Always end an HTTP function with send(), redirect(), or end(). Otherwise, your function might to continue to run and be forcibly terminated by the system
see https://firebase.google.com/docs/functions/http-events#terminate_http_functions
This might depend on the firebase-tools version that you are using, but looks familiar to this Github issue
The solution for it is to either upgrade to the latest version of the CLI or use the workaround solution:
Go to https://cloud.google.com/console/iam-admin/serviceaccounts
Click “Create service account”, give it a name (e.g. emulator), give it the Project>Owner role.Check “Furnish a new private key”, pick “JSON”.
Save the file somewhere on your computer
Run export GOOGLE_APPLICATION_CREDENTIALS="absolute/path/to/file.json"
Run firebase serve --only functions

Resources