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.
Related
I'm new to firebase and there is something I can't do. I want to send a notification to the phone with firebase functions. I want to receive notifications on the phone when someone follows me. My Firebase collection is as in the photo. I want to access the Followers array and send its information with notification. The codes I could write are as follows. What do I need to add?
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
exports.sendPushNotification = functions.firestore.document('/users/{uid}').onCreate((snap, context) => {
var values = snap.data();
var token = values.fcmTokens;
var payload = {
notification: {
title: values.title,
body: values.message
}
}
return admin.messaging().sendToDevice(token, payload);
});
First, onCreate() function is triggered when a document is created. I assume followers array will be updated everytime someone follows a user? In that case you should be using onUpdate() that'll trigger the function when the document is updated. You can just check if length of followers array has changed in the update, if yes then send the notification as shown below:
exports.sendPushNotification = functions.firestore
.document('users/{userId}')
.onUpdate((change, context) => {
const newValue = change.after.data();
const previousValue = change.before.data();
if (newValue.followers.length > previousValue.followers.length) {
// followers count increased, send notification
const token = newValue.fcmTokens;
const payload = {
notification: {
title: "New Follower",
body: "Someone followed you"
}
}
await admin.messaging().sendToDevice(token, payload);
}
return null;
});
Here, we send notification only if the followers field has changed since this function will trigger whenever any field in this user document is updated.
If you want to specify who followed the user, then you'll have to find the new UID added in followers array and query that user's data.
Firestore documents have a max size limit of 1 MB so if a user can have many followers then I'll recommend creating a followers sub-collection. Then you'll be able to use onCreate() on the sub-document path /users/{userId}/followers/{followerId}
I have a firebase function that is triggered with onCreate method. In this function, I am copying over user data into firestore. Everything works fine, except when I try to add a new element to the user object (even though no errors are thrown) the new firestore document does not show the added element.
Here is my firestore function:
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.newUser = functions.auth.user().onCreate((user)=>{
// create new variable
let currentUser = user;
//add hasSeenProfileUpdate element to the currentUser. This is what I need to add and ultimately save in the firestore
currentUser.hasSeenProfileUpdate = false;
return db
.collection("user")
.doc(user.uid)
.create(JSON.parse(JSON.stringify(currentUser)))
})
The function runs fine and the currentUser is saved to firestore. However the hasSeenProfileUpdate element does not show up in firestore. The console.log on currentUser also doesn't show the new element.
Any help is greatly appreciated!
(Thanks to #Dharmaraj) Posting refactored code that works Now:
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.newUser = functions.auth.user().onCreate((user)=>{
const currentUser = JSON.parse(JSON.stringify(user));
return db
.collection("user")
.doc(user.uid)
.create({
...currentUser,
hasSeenProfileUpdate: false
})
})
So far I have written the following code:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
exports.addAccount = functions.auth.user().onCreate((event) => {
const user = event.data; // The firebase user
const id = user.uid;
return admin
.database()
.ref("/users/" + id)
.set("ok");
});
The idea here is to execute a cloud function once a new user gets created. As this happens, I want to create a new node in the Firestore database. Under the 'users' collection I want to add a document with the uid, which contains a bit of information, in this case a String that says 'ok'.
When deploying this function it produces an error. How exactly should I go about creating it?
The admin.database() returns the Realtime Database service. To use Firestore, use firebase.firestore(). Try refactoring the code as shown below:
exports.addAccount = functions.auth.user().onCreate((event) => {
const user = event.data; // The firebase user
const id = user.uid;
return admin
.firestore()
.collection("users")
.doc(id)
.set({ uid: id, ...user });
});
I have this function of Firebase Firestore, every time a new document is created in the collection pagos I am sending a transactional email through Sendgrid with the data of this new document created. It works well.
My question is how do I do the same function, that is, to send said email but only when the document is updated with a certain field (for example dataPago) Can it be done?
Here my function when creating a document:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const SENDGRID_API_KEY = functions.config().sendgrid.key
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(SENDGRID_API_KEY);
exports.pagoRealizado = functions.firestore
.document('pagos/{pagoId}')
.onCreate((snap, context) => {
const pagoId = context.params.pagoId;
const db = admin.firestore()
return db.collection('pagos').doc(pagoId)
.get()
.then(doc => {
const pago = doc.data();
const msg = {
from: 'xxx#gmail.com',
to: 'xxx#xxx.com',
templateId: 'd-3473a9cc588245b7b2a6633f05dafdd8',
substitutionWrappers: ['{{', '}}'],
dynamic_template_data: {
nombre: pago.dataCliente.nombre,
}
};
return sgMail.send(msg)
})
.then(() => console.log('email enviado!'))
.catch(err => console.log(err))
});
Instead of using an onCreate trigger, you can use an onUpdate trigger. This will fire whenever a matched document is changed in some way, but not created or deleted. You can read more about each kind of Firestore trigger in the documentation.
You can't set up a trigger on specific field in a document. The trigger will fire when any field in the document changes in any way. You will have to check the before and after states of the document snapshots delivered to the function in order to figure out if it's a change you want to act on. Again, the documentation talks about this in more detail.
Simple cloud function to get database data is not working.
getusermessage() is not working
Error:
Function execution took 60002 ms, finished with status: 'timeout'
Index.JS for getting database result.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const cors = require('cors')({origin: true});
// Take the text parameter passed to this HTTP endpoint and insert it into the
// Realtime Database under the path /messages/:pushId/original
exports.addMessage = functions.https.onRequest((req, res) => {
// Grab the text parameter.
const original = req.query.text;
// Push the new message into the Realtime Database using the Firebase Admin SDK.
admin.database().ref('/messages').push({original: original}).then(snapshot => {
// Redirect with 303 SEE OTHER to the URL of the pushed object in the Firebase console.
res.redirect(303, snapshot.ref);
});
});
// 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();
// 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);
});
var db = admin.database();
exports.getUserMessage = functions.https.onRequest((req, res) => {
var query = db.ref("messages").orderByKey();
query.once("value")
.then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var key = childSnapshot.key;
// childData will be the actual contents of the child
var childData = childSnapshot.val();
});
});
});
What am O doing wrong?
You didn't say which of your three functions is timing out, but I'll take a guess at which one. Your HTTPS function getUserMessage isn't generating a response to the client. Cloud Functions will wait for 60 seconds (by default) for it to generate a response, and if it doesn't, it will kill the function and leave that message in the log.
Every code path in an HTTPS function should generate some response to the client.
You can set the timeout and memory using runWith during function declaration,
exports.getUserMessage = functions.runWith({ memory: '2GB', timeoutSeconds: 360 }).https.onRequest(