Firebase Function Not logs any data? - javascript

I write a function to send a notification to specific users so when I want to test it and log data I can't see it on Logs So what's the problem?
I just trigger databases when I create new order it should log order data but sadly not got anything
just i can see this log! I don't know it's for just deploy or something else
Code
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const serviceAccount = require('./serviceAccountKey.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: 'https://app-9d540.firebaseio.com',
});
// Send notification for user when his order accepted "status : pendding"
exports.acceptOrder = functions.database
.ref('/Providers/ProvidersOrders/InProgress/{providerUid}')
.onCreate((snapshot, context) => {
console.log('snapshot', snapshot.val());
const {providerUid} = context.params;
console.log('providerUid', providerUid);
return null;
});

The function you show gets triggered when you create a provider, not when you create an order. In other words: the first time you create an order for a provider, the provider node also gets created and your function gets triggered. But if you subsequently add another order to the same provider, your function won't get triggered, since the provider already exists.
If you want to trigger this function on the creation of an order, use this:
exports.acceptOrder = functions.database
.ref('/Providers/ProvidersOrders/InProgress/{providerUid}/{orderId}')
.onCreate((snapshot, context) => {
...

Related

Firebase onWrite not triggered

I read all the answers I found about this but I still have some problems. Probably something with .ref(), but I can't see what I'm doing wrong. My cloud function is not triggered at all.
DB example:
business/{businessId}/reservations/{reservationId}
I want to trigger this function every time when a new reservation is created [a new document is created in reservation collection] (business/{businessId}/reservations/).
And then I want to sent a notification message, but that is another thing.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
exports.sendAdminNotification = functions.database
.ref("business/{businessId}/reservations")
.onWrite((event: any) => {
// It never comes here...
console.log('Here');
const payload = {
notification: {
title: 'New registration',
body: 'You have new registration!',
},
};
// You can ignore this part
admin
.messaging()
.sendToDevice('SomeToken', payload)
.catch(function (error: any) {
console.log('Notification sent failed:', error);
});
});
The fact that you're using the terms "document" and "collection" suggests that your database is Firestore. But what you've written here is a Realtime Database trigger. Realtime Database is a completely different database. Instead, you will need to write a Firestore trigger instead. They begin with functions.firestore.

Adding a custom claim to the onCreate user firebase cloud function

I am trying on a firebase cloud function to add some custom claims when a new user is created. As the custom claims I need to add a User role to the created user
I have tried on some tutorials where user role is added after the user created. https://www.youtube.com/watch?v=4wa3CMK4E2Y. But I thought of adding custom claims on the creation of the user and returning with the response
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.addDefaultUserRole = functions.auth.user().onCreate((user) => {
let uid = user.uid;
//add custom claims
return admin.auth().setCustomUserClaims(uid,{
isAdmin: true,
});
});
Even the above code get executed in firebase, nothing happened and claims were not received in the response. Is it not a good practice to add custom claims on User creation? What will be the reason for not attaching the custom claims with the above code
Your Cloud Function code looks OK and the Custom Claim shall be correctly set.
The problem you seem to encounter is that you cannot confirm that the claim is correctly set. As a matter of fact the setCustomUserClaims() method returns a non-null Promise containing void (and nothing else!).
You could do as follows if you want to verify, through the Log, that the claim has been correctly set.
exports.addDefaultUserRole = functions.auth.user().onCreate((user) => {
let uid = user.uid;
//add custom claims
return admin.auth().setCustomUserClaims(uid,{
isAdmin: true
})
.then(() => {
//Interesting to note: we need to re-fetch the userRecord, as the user variable **does not** hold the claim
return admin.auth().getUser(uid);
})
.then(userRecord => {
console.log(uid);
console.log(userRecord.customClaims.isAdmin);
return null;
});
});
Finally, note that it is not at all a "bad practice" to add custom claims on User creation! It makes full sense to do that upon user creation when you know which Claim(s) to set.
exports.addDefaultUserRole = functions.auth.user().onCreate((user) => {
let uid = user.uid;
//add custom claims
return admin.auth().setCustomUserClaims(uid,{
isAdmin: true
})
.then(() => {
//Interesting to note: we need to re-fetch the userRecord, as the user variable **does not** hold the claim
return admin.auth().getUser(uid);
})
.then(userRecord => {
console.log(uid);
console.log(userRecord.customClaims.isAdmin);
return null;
Hope it works.

Firebase Cloud Function in Javascript. Remove() function not working

I have a Firebase cloud function. Everything works as expected within the helloWorld function except the line deedRef.limitToLast(1).remove(); I also tried to do .ref(/deeds/${deedID}).remove() is there a reason why I can't remove data from firebase within cloud functions? The output from the http request is "Error: could not handle the request".
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const deedRef = admin.database().ref('/deeds');
const oldDeedRef = admin.database().ref('/oldDeeds');
exports.helloWorld = functions.https.onRequest((req, res) => {
deedRef.limitToLast(1).once("value", (snapshot) => {
snapshot.forEach((deedSnapshot) =>{
let deedID = deedSnapshot.val().id;
let text = deedSnapshot.val().message;
oldDeedRef.push({
id: deedID,
message: text
})
})
})
deedRef.limitToLast(1).remove();
res.send("Congrats For running the function");
});
The problem has nothing to do with Cloud Functions.
deedRef.limitToLast(1) returns a Query type object. Query doesn't have a method called remove(). Therefore, your code will fail at runtime with a message to that effect.
If you want to delete some data from Realtime Database, you're going to need a Reference type object, which has a remove() method. This will remove everything at the location of the reference.

How to access multiple Realtime Database instances in Cloud Functions for Firebase

I'm using multiple databases in a Firebase project. Cloud functions for the main (default) database work great, however, I cannot make them work for a secondary database. For example I want to make a read request on a node with admin privileges:
//this works
admin.database().ref(nodePath).once('value')...
This works in the main database, however, if I want to execute the command on another database, it doesn't work:
//this doesn't work
admin.database(secondaryDatabaseUrl).ref(nodePath).once('value')...
Although the functions are deployed, I get an error on the console when trying to execute the cloud function.
Here's the code for the cloud function with an https trigger:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const secureCompare = require('secure-compare');
exports.testFunction= functions.https.onRequest((req, res) => {
const key = req.query.key;
// Exit if the keys don't match
if (!secureCompare(key, functions.config().cron.key)) {
console.error('keys do not match');
res.status(403).send('error1');
return;
}
//test read request
//the line below crashes the function
return admin.database('https://secondary_db_url.firebaseio.com').ref(`/testNode`).once('value').then(dataSnapshot=> {
console.log('value', dataSnapshot.val());
return;
}).catch(er => {
console.error('error', er);
res.status(403).send('error2');
});
});
Below is the error log in the Firebase console:
TypeError: ns.ensureApp(...).database is not a function
at FirebaseNamespace.fn (/user_code/node_modules/firebase-admin/lib/firebase-namespace.js:251:42)
at exports.testFunction.functions.https.onRequest (/user_code/index.js:16:16)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/providers/https.js:26:41)
at /var/tmp/worker/worker.js:671:7
at /var/tmp/worker/worker.js:655:9
at _combinedTickCallback (internal/process/next_tick.js:73:7)
at process._tickDomainCallback (internal/process/next_tick.js:128:9)
If I don't specify the secondary database URL, the function will make the read request on my main database which works great:
//this works
return admin.database().ref(`/testNode`).once('value').then(dataSnapshot=> {
...
I'm using the latest SDK versions: "firebase-admin": "^5.5.1" and "firebase-functions": "^0.7.3"
So, how do I get an instance of a secondary database in cloud functions using admin privileges?
Here's how to access database by URL using Admin SDK:
let app = admin.app();
let ref = app.database('https://secondary_db_url.firebaseio.com').ref();
Here's an example from Admin SDK integration tests: https://github.com/firebase/firebase-admin-node/blob/master/test/integration/database.js#L52
With cloud functions > 1.1 now, here is the documentation link that saved my life on this issue.
https://firebase.google.com/docs/database/usage/sharding#connect_your_app_to_multiple_database_instances
So, it looks like this at the top of my my cloud function index.js :
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const dev = admin.initializeApp({
databaseURL: "https://appdev.firebaseio.com"
}, 'dev');
const v2 = admin.initializeApp({
databaseURL: "https://appv2.firebaseio.com"
}, 'v2');
and then, in my clond functions functions code I can do :
//will change stuff on default database
admin.database().ref().child(`stuff/${stuffId}`).set(myStuff)
//will change stuff on my dev database
admin.database(dev).ref().child(`stuff/${stuffId}`).set(myStuff)
//will change stuff on my v2 database
admin.database(v2).ref().child(`stuff/${stuffId}`).set(myStuff)
So it looks like you are trying to access multiple databases using the javascript web client API. Passing the URL of the database to the API like this doesn't work with the Admin SDK:
admin.database('https://secondary_db_url.firebaseio.com').ref(`/testNode`)
Instead, you have to initialize a second app, give it a name, and pass that app around to the Admin SDK APIs. Here's a complete sample that writes the same data to two different database instances in the same project:
const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase)
const otherConfig = Object.assign({}, functions.config().firebase)
otherConfig.databaseURL = 'https://your-other-db.firebaseio.com/'
const otherApp = admin.initializeApp(otherConfig, 'otherAppName')
exports.foo = functions.https.onRequest((req, res) => {
const data = { foo: 'bar' }
const p1 = admin.database().ref('data').set(data)
const p2 = admin.database(otherApp).ref('data').set(data)
Promise.all([p1, p2]).then(() => {
res.send("OK")
})
.catch(error => {
res.status(500).send(error)
})
})
Updating this while on Firebase Functions v3.14.0. None of this answers worked for me so I implemented this solution
instance Registers a function that triggers on events from a specific Firebase Realtime Database instance
functions.database.instance('my-app-db-2').ref('/foo/bar')
Use the name of the database instance and it works, no need for the url. functions.database.ref used without instance watches the default instance for events.
So if both the answers doesn't work.
What happened with me is both the method worked without any error but second instance of database was not getting updated.
I updated npm and firebase CLI it worked.
Also #Dough Stevenson you Passing the URL of the database to the API like this **does** work with the Admin SDK
And this is a good blog from Firebase about the same
Firebase Blog : Easier scaling with multi-database support!

How to run query from inside of Cloud function?

I'd like to perform a query on my database once a cloud function on my Firebase app is called.
Let's say I have a certain trigger on the database, consider the example provided in the get started guide on Firebase.
// Listens for new messages added to /messages/:pushId/original and creates an
// uppercase version of the message to /messages/:pushId/uppercase
exports.makeUppercase = functions.database.ref('/messages/{pushId}/original')
.onWrite(event => {
// Grab the current value of what was written to the Realtime Database.
const original = event.data.val();
console.log('Uppercasing', event.params.pushId, original);
const uppercase = original.toUpperCase();
// I'D LIKE TO PERFORM A QUERY HERE, JUST A SIMPLE RETRIEVE BASED ON THE ID PROVIDED
// 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 event.data.ref.parent.child('uppercase').set(uppercase);
});
Which modules should I import, if any?
How can I perform the query on the DB?
Thank you in advance for your answer!
You can use the Node.js Admin SDK for this:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.makeUppercase = functions.database()
.ref('/messages/{pushId}/original')
.onWrite(event => {
return admin.database().ref('/other')
.orderByChild('id').equalTo(event.params.pushId)
.once('value').then(snapshot => {
// there, I queried!
});
});

Categories

Resources